1228753Smm/*- 2231200Smm * Copyright (c) 2003-2010 Tim Kientzle 3248616Smm * Copyright (c) 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 28228753Smm#include "archive_platform.h" 29231200Smm__FBSDID("$FreeBSD$"); 30228753Smm 31231200Smm#if !defined(_WIN32) || defined(__CYGWIN__) 32231200Smm 33228753Smm#ifdef HAVE_SYS_TYPES_H 34228753Smm#include <sys/types.h> 35228753Smm#endif 36248616Smm#ifdef HAVE_SYS_ACL_H 37248616Smm#include <sys/acl.h> 38248616Smm#endif 39228753Smm#ifdef HAVE_SYS_EXTATTR_H 40228753Smm#include <sys/extattr.h> 41228753Smm#endif 42316338Smm#if HAVE_SYS_XATTR_H 43228753Smm#include <sys/xattr.h> 44316338Smm#elif HAVE_ATTR_XATTR_H 45248616Smm#include <attr/xattr.h> 46228753Smm#endif 47231200Smm#ifdef HAVE_SYS_EA_H 48231200Smm#include <sys/ea.h> 49231200Smm#endif 50228753Smm#ifdef HAVE_SYS_IOCTL_H 51228753Smm#include <sys/ioctl.h> 52228753Smm#endif 53228753Smm#ifdef HAVE_SYS_STAT_H 54228753Smm#include <sys/stat.h> 55228753Smm#endif 56228753Smm#ifdef HAVE_SYS_TIME_H 57228753Smm#include <sys/time.h> 58228753Smm#endif 59228753Smm#ifdef HAVE_SYS_UTIME_H 60228753Smm#include <sys/utime.h> 61228753Smm#endif 62231200Smm#ifdef HAVE_COPYFILE_H 63231200Smm#include <copyfile.h> 64231200Smm#endif 65228753Smm#ifdef HAVE_ERRNO_H 66228753Smm#include <errno.h> 67228753Smm#endif 68228753Smm#ifdef HAVE_FCNTL_H 69228753Smm#include <fcntl.h> 70228753Smm#endif 71228753Smm#ifdef HAVE_GRP_H 72228753Smm#include <grp.h> 73228753Smm#endif 74231200Smm#ifdef HAVE_LANGINFO_H 75231200Smm#include <langinfo.h> 76231200Smm#endif 77228753Smm#ifdef HAVE_LINUX_FS_H 78228753Smm#include <linux/fs.h> /* for Linux file flags */ 79228753Smm#endif 80228753Smm/* 81228753Smm * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 82228753Smm * As the include guards don't agree, the order of include is important. 83228753Smm */ 84228753Smm#ifdef HAVE_LINUX_EXT2_FS_H 85228753Smm#include <linux/ext2_fs.h> /* for Linux file flags */ 86228753Smm#endif 87228753Smm#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 88228753Smm#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ 89228753Smm#endif 90228753Smm#ifdef HAVE_LIMITS_H 91228753Smm#include <limits.h> 92228753Smm#endif 93228753Smm#ifdef HAVE_PWD_H 94228753Smm#include <pwd.h> 95228753Smm#endif 96228753Smm#include <stdio.h> 97228753Smm#ifdef HAVE_STDLIB_H 98228753Smm#include <stdlib.h> 99228753Smm#endif 100228753Smm#ifdef HAVE_STRING_H 101228753Smm#include <string.h> 102228753Smm#endif 103228753Smm#ifdef HAVE_UNISTD_H 104228753Smm#include <unistd.h> 105228753Smm#endif 106228753Smm#ifdef HAVE_UTIME_H 107228753Smm#include <utime.h> 108228753Smm#endif 109231200Smm#ifdef F_GETTIMES /* Tru64 specific */ 110231200Smm#include <sys/fcntl1.h> 111231200Smm#endif 112228753Smm 113313571Smm/* 114313571Smm * Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared. 115313571Smm * 116313571Smm * It assumes that the input is an integer type of no more than 64 bits. 117313571Smm * If the number is less than zero, t must be a signed type, so it fits in 118313571Smm * int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t 119313571Smm * without loss. But it could be a large unsigned value, so we have to clip it 120313571Smm * to INT64_MAX.* 121313571Smm */ 122313571Smm#define to_int64_time(t) \ 123313571Smm ((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t)) 124313571Smm 125231200Smm#if __APPLE__ 126231200Smm#include <TargetConditionals.h> 127231200Smm#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H 128231200Smm#include <quarantine.h> 129231200Smm#define HAVE_QUARANTINE 1 130231200Smm#endif 131231200Smm#endif 132231200Smm 133248616Smm#ifdef HAVE_ZLIB_H 134248616Smm#include <zlib.h> 135248616Smm#endif 136248616Smm 137231200Smm/* TODO: Support Mac OS 'quarantine' feature. This is really just a 138231200Smm * standard tag to mark files that have been downloaded as "tainted". 139231200Smm * On Mac OS, we should mark the extracted files as tainted if the 140231200Smm * archive being read was tainted. Windows has a similar feature; we 141231200Smm * should investigate ways to support this generically. */ 142231200Smm 143228753Smm#include "archive.h" 144231200Smm#include "archive_acl_private.h" 145228753Smm#include "archive_string.h" 146248616Smm#include "archive_endian.h" 147228753Smm#include "archive_entry.h" 148228753Smm#include "archive_private.h" 149238909Smm#include "archive_write_disk_private.h" 150228753Smm 151228753Smm#ifndef O_BINARY 152228753Smm#define O_BINARY 0 153228753Smm#endif 154248616Smm#ifndef O_CLOEXEC 155306322Smm#define O_CLOEXEC 0 156248616Smm#endif 157228753Smm 158306322Smm/* Ignore non-int O_NOFOLLOW constant. */ 159306322Smm/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */ 160306322Smm#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX) 161306322Smm#undef O_NOFOLLOW 162306322Smm#endif 163306322Smm 164306322Smm#ifndef O_NOFOLLOW 165306322Smm#define O_NOFOLLOW 0 166306322Smm#endif 167306322Smm 168349525Smm#ifndef AT_FDCWD 169349525Smm#define AT_FDCWD -100 170349525Smm#endif 171349525Smm 172228753Smmstruct fixup_entry { 173228753Smm struct fixup_entry *next; 174231200Smm struct archive_acl acl; 175228753Smm mode_t mode; 176228753Smm int64_t atime; 177228753Smm int64_t birthtime; 178228753Smm int64_t mtime; 179231200Smm int64_t ctime; 180228753Smm unsigned long atime_nanos; 181228753Smm unsigned long birthtime_nanos; 182228753Smm unsigned long mtime_nanos; 183231200Smm unsigned long ctime_nanos; 184228753Smm unsigned long fflags_set; 185231200Smm size_t mac_metadata_size; 186231200Smm void *mac_metadata; 187228753Smm int fixup; /* bitmask of what needs fixing */ 188228753Smm char *name; 189228753Smm}; 190228753Smm 191228753Smm/* 192228753Smm * We use a bitmask to track which operations remain to be done for 193228753Smm * this file. In particular, this helps us avoid unnecessary 194228753Smm * operations when it's possible to take care of one step as a 195228753Smm * side-effect of another. For example, mkdir() can specify the mode 196228753Smm * for the newly-created object but symlink() cannot. This means we 197228753Smm * can skip chmod() if mkdir() succeeded, but we must explicitly 198228753Smm * chmod() if we're trying to create a directory that already exists 199228753Smm * (mkdir() failed) or if we're restoring a symlink. Similarly, we 200228753Smm * need to verify UID/GID before trying to restore SUID/SGID bits; 201228753Smm * that verification can occur explicitly through a stat() call or 202228753Smm * implicitly because of a successful chown() call. 203228753Smm */ 204228753Smm#define TODO_MODE_FORCE 0x40000000 205228753Smm#define TODO_MODE_BASE 0x20000000 206228753Smm#define TODO_SUID 0x10000000 207228753Smm#define TODO_SUID_CHECK 0x08000000 208228753Smm#define TODO_SGID 0x04000000 209228753Smm#define TODO_SGID_CHECK 0x02000000 210248616Smm#define TODO_APPLEDOUBLE 0x01000000 211228753Smm#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID) 212228753Smm#define TODO_TIMES ARCHIVE_EXTRACT_TIME 213228753Smm#define TODO_OWNER ARCHIVE_EXTRACT_OWNER 214228753Smm#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS 215228753Smm#define TODO_ACLS ARCHIVE_EXTRACT_ACL 216228753Smm#define TODO_XATTR ARCHIVE_EXTRACT_XATTR 217231200Smm#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA 218248616Smm#define TODO_HFS_COMPRESSION ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED 219228753Smm 220228753Smmstruct archive_write_disk { 221228753Smm struct archive archive; 222228753Smm 223228753Smm mode_t user_umask; 224228753Smm struct fixup_entry *fixup_list; 225228753Smm struct fixup_entry *current_fixup; 226231200Smm int64_t user_uid; 227231200Smm int skip_file_set; 228238856Smm int64_t skip_file_dev; 229238856Smm int64_t skip_file_ino; 230228753Smm time_t start_time; 231228753Smm 232231200Smm int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid); 233228753Smm void (*cleanup_gid)(void *private); 234228753Smm void *lookup_gid_data; 235231200Smm int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid); 236228753Smm void (*cleanup_uid)(void *private); 237228753Smm void *lookup_uid_data; 238228753Smm 239228753Smm /* 240228753Smm * Full path of last file to satisfy symlink checks. 241228753Smm */ 242228753Smm struct archive_string path_safe; 243228753Smm 244228753Smm /* 245228753Smm * Cached stat data from disk for the current entry. 246228753Smm * If this is valid, pst points to st. Otherwise, 247228753Smm * pst is null. 248228753Smm */ 249228753Smm struct stat st; 250228753Smm struct stat *pst; 251228753Smm 252228753Smm /* Information about the object being restored right now. */ 253228753Smm struct archive_entry *entry; /* Entry being extracted. */ 254228753Smm char *name; /* Name of entry, possibly edited. */ 255228753Smm struct archive_string _name_data; /* backing store for 'name' */ 256358090Smm char *tmpname; /* Temporary name * */ 257358090Smm struct archive_string _tmpname_data; /* backing store for 'tmpname' */ 258228753Smm /* Tasks remaining for this object. */ 259228753Smm int todo; 260228753Smm /* Tasks deferred until end-of-archive. */ 261228753Smm int deferred; 262228753Smm /* Options requested by the client. */ 263228753Smm int flags; 264228753Smm /* Handle for the file we're restoring. */ 265228753Smm int fd; 266228753Smm /* Current offset for writing data to the file. */ 267231200Smm int64_t offset; 268228753Smm /* Last offset actually written to disk. */ 269231200Smm int64_t fd_offset; 270231200Smm /* Total bytes actually written to files. */ 271231200Smm int64_t total_bytes_written; 272228753Smm /* Maximum size of file, -1 if unknown. */ 273231200Smm int64_t filesize; 274228753Smm /* Dir we were in before this restore; only for deep paths. */ 275228753Smm int restore_pwd; 276228753Smm /* Mode we should use for this entry; affected by _PERM and umask. */ 277228753Smm mode_t mode; 278228753Smm /* UID/GID to use in restoring this entry. */ 279231200Smm int64_t uid; 280231200Smm int64_t gid; 281248616Smm /* 282248616Smm * HFS+ Compression. 283248616Smm */ 284248616Smm /* Xattr "com.apple.decmpfs". */ 285248616Smm uint32_t decmpfs_attr_size; 286248616Smm unsigned char *decmpfs_header_p; 287248616Smm /* ResourceFork set options used for fsetxattr. */ 288248616Smm int rsrc_xattr_options; 289248616Smm /* Xattr "com.apple.ResourceFork". */ 290248616Smm unsigned char *resource_fork; 291248616Smm size_t resource_fork_allocated_size; 292248616Smm unsigned int decmpfs_block_count; 293248616Smm uint32_t *decmpfs_block_info; 294248616Smm /* Buffer for compressed data. */ 295248616Smm unsigned char *compressed_buffer; 296248616Smm size_t compressed_buffer_size; 297248616Smm size_t compressed_buffer_remaining; 298248616Smm /* The offset of the ResourceFork where compressed data will 299248616Smm * be placed. */ 300248616Smm uint32_t compressed_rsrc_position; 301248616Smm uint32_t compressed_rsrc_position_v; 302248616Smm /* Buffer for uncompressed data. */ 303248616Smm char *uncompressed_buffer; 304248616Smm size_t block_remaining_bytes; 305248616Smm size_t file_remaining_bytes; 306248616Smm#ifdef HAVE_ZLIB_H 307248616Smm z_stream stream; 308248616Smm int stream_valid; 309248616Smm int decmpfs_compression_level; 310248616Smm#endif 311228753Smm}; 312228753Smm 313228753Smm/* 314228753Smm * Default mode for dirs created automatically (will be modified by umask). 315231200Smm * Note that POSIX specifies 0777 for implicitly-created dirs, "modified 316228753Smm * by the process' file creation mask." 317228753Smm */ 318228753Smm#define DEFAULT_DIR_MODE 0777 319228753Smm/* 320228753Smm * Dir modes are restored in two steps: During the extraction, the permissions 321228753Smm * in the archive are modified to match the following limits. During 322228753Smm * the post-extract fixup pass, the permissions from the archive are 323228753Smm * applied. 324228753Smm */ 325228753Smm#define MINIMUM_DIR_MODE 0700 326228753Smm#define MAXIMUM_DIR_MODE 0775 327228753Smm 328248616Smm/* 329313571Smm * Maximum uncompressed size of a decmpfs block. 330248616Smm */ 331248616Smm#define MAX_DECMPFS_BLOCK_SIZE (64 * 1024) 332248616Smm/* 333248616Smm * HFS+ compression type. 334248616Smm */ 335248616Smm#define CMP_XATTR 3/* Compressed data in xattr. */ 336248616Smm#define CMP_RESOURCE_FORK 4/* Compressed data in resource fork. */ 337248616Smm/* 338248616Smm * HFS+ compression resource fork. 339248616Smm */ 340248616Smm#define RSRC_H_SIZE 260 /* Base size of Resource fork header. */ 341248616Smm#define RSRC_F_SIZE 50 /* Size of Resource fork footer. */ 342248616Smm/* Size to write compressed data to resource fork. */ 343248616Smm#define COMPRESSED_W_SIZE (64 * 1024) 344313571Smm/* decmpfs definitions. */ 345248616Smm#define MAX_DECMPFS_XATTR_SIZE 3802 346248616Smm#ifndef DECMPFS_XATTR_NAME 347248616Smm#define DECMPFS_XATTR_NAME "com.apple.decmpfs" 348248616Smm#endif 349248616Smm#define DECMPFS_MAGIC 0x636d7066 350248616Smm#define DECMPFS_COMPRESSION_MAGIC 0 351248616Smm#define DECMPFS_COMPRESSION_TYPE 4 352248616Smm#define DECMPFS_UNCOMPRESSED_SIZE 8 353248616Smm#define DECMPFS_HEADER_SIZE 16 354248616Smm 355248616Smm#define HFS_BLOCKS(s) ((s) >> 12) 356248616Smm 357349525Smm 358349525Smmstatic int la_opendirat(int, const char *); 359358090Smmstatic int la_mktemp(struct archive_write_disk *); 360309702Smmstatic void fsobj_error(int *, struct archive_string *, int, const char *, 361309702Smm const char *); 362309702Smmstatic int check_symlinks_fsobj(char *, int *, struct archive_string *, 363309702Smm int); 364228753Smmstatic int check_symlinks(struct archive_write_disk *); 365228753Smmstatic int create_filesystem_object(struct archive_write_disk *); 366309702Smmstatic struct fixup_entry *current_fixup(struct archive_write_disk *, 367309702Smm const char *pathname); 368231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX) 369228753Smmstatic void edit_deep_directories(struct archive_write_disk *ad); 370228753Smm#endif 371309702Smmstatic int cleanup_pathname_fsobj(char *, int *, struct archive_string *, 372309702Smm int); 373228753Smmstatic int cleanup_pathname(struct archive_write_disk *); 374228753Smmstatic int create_dir(struct archive_write_disk *, char *); 375228753Smmstatic int create_parent_dir(struct archive_write_disk *, char *); 376248616Smmstatic ssize_t hfs_write_data_block(struct archive_write_disk *, 377248616Smm const char *, size_t); 378248616Smmstatic int fixup_appledouble(struct archive_write_disk *, const char *); 379228753Smmstatic int older(struct stat *, struct archive_entry *); 380228753Smmstatic int restore_entry(struct archive_write_disk *); 381231200Smmstatic int set_mac_metadata(struct archive_write_disk *, const char *, 382231200Smm const void *, size_t); 383228753Smmstatic int set_xattrs(struct archive_write_disk *); 384302001Smmstatic int clear_nochange_fflags(struct archive_write_disk *); 385228753Smmstatic int set_fflags(struct archive_write_disk *); 386228753Smmstatic int set_fflags_platform(struct archive_write_disk *, int fd, 387228753Smm const char *name, mode_t mode, 388228753Smm unsigned long fflags_set, unsigned long fflags_clear); 389228753Smmstatic int set_ownership(struct archive_write_disk *); 390228753Smmstatic int set_mode(struct archive_write_disk *, int mode); 391228753Smmstatic int set_time(int, int, const char *, time_t, long, time_t, long); 392231200Smmstatic int set_times(struct archive_write_disk *, int, int, const char *, 393231200Smm time_t, long, time_t, long, time_t, long, time_t, long); 394231200Smmstatic int set_times_from_entry(struct archive_write_disk *); 395228753Smmstatic struct fixup_entry *sort_dir_list(struct fixup_entry *p); 396228753Smmstatic ssize_t write_data_block(struct archive_write_disk *, 397228753Smm const char *, size_t); 398228753Smm 399228753Smmstatic struct archive_vtable *archive_write_disk_vtable(void); 400228753Smm 401231200Smmstatic int _archive_write_disk_close(struct archive *); 402231200Smmstatic int _archive_write_disk_free(struct archive *); 403309702Smmstatic int _archive_write_disk_header(struct archive *, 404309702Smm struct archive_entry *); 405231200Smmstatic int64_t _archive_write_disk_filter_bytes(struct archive *, int); 406231200Smmstatic int _archive_write_disk_finish_entry(struct archive *); 407309702Smmstatic ssize_t _archive_write_disk_data(struct archive *, const void *, 408309702Smm size_t); 409309702Smmstatic ssize_t _archive_write_disk_data_block(struct archive *, const void *, 410309702Smm size_t, int64_t); 411228753Smm 412228753Smmstatic int 413358090Smmla_mktemp(struct archive_write_disk *a) 414358090Smm{ 415358090Smm int oerrno, fd; 416358090Smm mode_t mode; 417358090Smm 418358090Smm archive_string_empty(&a->_tmpname_data); 419358090Smm archive_string_sprintf(&a->_tmpname_data, "%s.XXXXXX", a->name); 420358090Smm a->tmpname = a->_tmpname_data.s; 421358090Smm 422358090Smm fd = __archive_mkstemp(a->tmpname); 423358090Smm if (fd == -1) 424358090Smm return -1; 425358090Smm 426358090Smm mode = a->mode & 0777 & ~a->user_umask; 427358090Smm if (fchmod(fd, mode) == -1) { 428358090Smm oerrno = errno; 429358090Smm close(fd); 430358090Smm errno = oerrno; 431358090Smm return -1; 432358090Smm } 433358090Smm return fd; 434358090Smm} 435358090Smm 436358090Smmstatic int 437349525Smmla_opendirat(int fd, const char *path) { 438349525Smm const int flags = O_CLOEXEC 439349525Smm#if defined(O_BINARY) 440349525Smm | O_BINARY 441349525Smm#endif 442349525Smm#if defined(O_DIRECTORY) 443349525Smm | O_DIRECTORY 444349525Smm#endif 445349525Smm#if defined(O_PATH) 446349525Smm | O_PATH 447349525Smm#elif defined(O_SEARCH) 448349525Smm | O_SEARCH 449358090Smm#elif defined(__FreeBSD__) && defined(O_EXEC) 450349525Smm | O_EXEC 451349525Smm#else 452349525Smm | O_RDONLY 453349525Smm#endif 454349525Smm ; 455349525Smm 456349525Smm#if !defined(HAVE_OPENAT) 457349525Smm if (fd != AT_FDCWD) { 458349525Smm errno = ENOTSUP; 459349525Smm return (-1); 460349525Smm } else 461353377Smm return (open(path, flags)); 462349525Smm#else 463349525Smm return (openat(fd, path, flags)); 464349525Smm#endif 465349525Smm} 466349525Smm 467349525Smmstatic int 468231200Smmlazy_stat(struct archive_write_disk *a) 469228753Smm{ 470228753Smm if (a->pst != NULL) { 471228753Smm /* Already have stat() data available. */ 472228753Smm return (ARCHIVE_OK); 473228753Smm } 474228753Smm#ifdef HAVE_FSTAT 475228753Smm if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) { 476228753Smm a->pst = &a->st; 477228753Smm return (ARCHIVE_OK); 478228753Smm } 479228753Smm#endif 480228753Smm /* 481228753Smm * XXX At this point, symlinks should not be hit, otherwise 482231200Smm * XXX a race occurred. Do we want to check explicitly for that? 483228753Smm */ 484228753Smm if (lstat(a->name, &a->st) == 0) { 485228753Smm a->pst = &a->st; 486228753Smm return (ARCHIVE_OK); 487228753Smm } 488228753Smm archive_set_error(&a->archive, errno, "Couldn't stat file"); 489228753Smm return (ARCHIVE_WARN); 490228753Smm} 491228753Smm 492228753Smmstatic struct archive_vtable * 493228753Smmarchive_write_disk_vtable(void) 494228753Smm{ 495228753Smm static struct archive_vtable av; 496228753Smm static int inited = 0; 497228753Smm 498228753Smm if (!inited) { 499231200Smm av.archive_close = _archive_write_disk_close; 500231200Smm av.archive_filter_bytes = _archive_write_disk_filter_bytes; 501231200Smm av.archive_free = _archive_write_disk_free; 502231200Smm av.archive_write_header = _archive_write_disk_header; 503231200Smm av.archive_write_finish_entry 504231200Smm = _archive_write_disk_finish_entry; 505231200Smm av.archive_write_data = _archive_write_disk_data; 506231200Smm av.archive_write_data_block = _archive_write_disk_data_block; 507231200Smm inited = 1; 508228753Smm } 509228753Smm return (&av); 510228753Smm} 511228753Smm 512231200Smmstatic int64_t 513231200Smm_archive_write_disk_filter_bytes(struct archive *_a, int n) 514231200Smm{ 515231200Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 516231200Smm (void)n; /* UNUSED */ 517231200Smm if (n == -1 || n == 0) 518231200Smm return (a->total_bytes_written); 519231200Smm return (-1); 520231200Smm} 521228753Smm 522231200Smm 523228753Smmint 524228753Smmarchive_write_disk_set_options(struct archive *_a, int flags) 525228753Smm{ 526228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 527228753Smm 528228753Smm a->flags = flags; 529228753Smm return (ARCHIVE_OK); 530228753Smm} 531228753Smm 532228753Smm 533228753Smm/* 534228753Smm * Extract this entry to disk. 535228753Smm * 536228753Smm * TODO: Validate hardlinks. According to the standards, we're 537228753Smm * supposed to check each extracted hardlink and squawk if it refers 538228753Smm * to a file that we didn't restore. I'm not entirely convinced this 539228753Smm * is a good idea, but more importantly: Is there any way to validate 540228753Smm * hardlinks without keeping a complete list of filenames from the 541228753Smm * entire archive?? Ugh. 542228753Smm * 543228753Smm */ 544228753Smmstatic int 545231200Smm_archive_write_disk_header(struct archive *_a, struct archive_entry *entry) 546228753Smm{ 547228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 548228753Smm struct fixup_entry *fe; 549368708Smm const char *linkname; 550228753Smm int ret, r; 551228753Smm 552231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 553228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 554228753Smm "archive_write_disk_header"); 555228753Smm archive_clear_error(&a->archive); 556228753Smm if (a->archive.state & ARCHIVE_STATE_DATA) { 557231200Smm r = _archive_write_disk_finish_entry(&a->archive); 558228753Smm if (r == ARCHIVE_FATAL) 559228753Smm return (r); 560228753Smm } 561228753Smm 562228753Smm /* Set up for this particular entry. */ 563228753Smm a->pst = NULL; 564228753Smm a->current_fixup = NULL; 565228753Smm a->deferred = 0; 566228753Smm if (a->entry) { 567228753Smm archive_entry_free(a->entry); 568228753Smm a->entry = NULL; 569228753Smm } 570228753Smm a->entry = archive_entry_clone(entry); 571228753Smm a->fd = -1; 572228753Smm a->fd_offset = 0; 573228753Smm a->offset = 0; 574231200Smm a->restore_pwd = -1; 575228753Smm a->uid = a->user_uid; 576228753Smm a->mode = archive_entry_mode(a->entry); 577228753Smm if (archive_entry_size_is_set(a->entry)) 578228753Smm a->filesize = archive_entry_size(a->entry); 579228753Smm else 580228753Smm a->filesize = -1; 581228753Smm archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry)); 582228753Smm a->name = a->_name_data.s; 583228753Smm archive_clear_error(&a->archive); 584228753Smm 585228753Smm /* 586228753Smm * Clean up the requested path. This is necessary for correct 587228753Smm * dir restores; the dir restore logic otherwise gets messed 588228753Smm * up by nonsense like "dir/.". 589228753Smm */ 590228753Smm ret = cleanup_pathname(a); 591228753Smm if (ret != ARCHIVE_OK) 592228753Smm return (ret); 593228753Smm 594228753Smm /* 595368708Smm * Check if we have a hardlink that points to itself. 596368708Smm */ 597368708Smm linkname = archive_entry_hardlink(a->entry); 598368708Smm if (linkname != NULL && strcmp(a->name, linkname) == 0) { 599368708Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 600368708Smm "Skipping hardlink pointing to itself: %s", 601368708Smm a->name); 602368708Smm return (ARCHIVE_WARN); 603368708Smm } 604368708Smm 605368708Smm /* 606231200Smm * Query the umask so we get predictable mode settings. 607228753Smm * This gets done on every call to _write_header in case the 608228753Smm * user edits their umask during the extraction for some 609231200Smm * reason. 610228753Smm */ 611231200Smm umask(a->user_umask = umask(0)); 612228753Smm 613228753Smm /* Figure out what we need to do for this entry. */ 614228753Smm a->todo = TODO_MODE_BASE; 615228753Smm if (a->flags & ARCHIVE_EXTRACT_PERM) { 616228753Smm a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ 617228753Smm /* 618228753Smm * SGID requires an extra "check" step because we 619228753Smm * cannot easily predict the GID that the system will 620228753Smm * assign. (Different systems assign GIDs to files 621228753Smm * based on a variety of criteria, including process 622228753Smm * credentials and the gid of the enclosing 623228753Smm * directory.) We can only restore the SGID bit if 624228753Smm * the file has the right GID, and we only know the 625228753Smm * GID if we either set it (see set_ownership) or if 626228753Smm * we've actually called stat() on the file after it 627228753Smm * was restored. Since there are several places at 628228753Smm * which we might verify the GID, we need a TODO bit 629228753Smm * to keep track. 630228753Smm */ 631228753Smm if (a->mode & S_ISGID) 632228753Smm a->todo |= TODO_SGID | TODO_SGID_CHECK; 633228753Smm /* 634228753Smm * Verifying the SUID is simpler, but can still be 635228753Smm * done in multiple ways, hence the separate "check" bit. 636228753Smm */ 637228753Smm if (a->mode & S_ISUID) 638228753Smm a->todo |= TODO_SUID | TODO_SUID_CHECK; 639228753Smm } else { 640228753Smm /* 641228753Smm * User didn't request full permissions, so don't 642228753Smm * restore SUID, SGID bits and obey umask. 643228753Smm */ 644228753Smm a->mode &= ~S_ISUID; 645228753Smm a->mode &= ~S_ISGID; 646228753Smm a->mode &= ~S_ISVTX; 647228753Smm a->mode &= ~a->user_umask; 648228753Smm } 649228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) 650228753Smm a->todo |= TODO_OWNER; 651228753Smm if (a->flags & ARCHIVE_EXTRACT_TIME) 652228753Smm a->todo |= TODO_TIMES; 653231200Smm if (a->flags & ARCHIVE_EXTRACT_ACL) { 654316338Smm#if ARCHIVE_ACL_DARWIN 655316338Smm /* 656316338Smm * On MacOS, platform ACLs get stored in mac_metadata, too. 657316338Smm * If we intend to extract mac_metadata and it is present 658316338Smm * we skip extracting libarchive NFSv4 ACLs. 659316338Smm */ 660316338Smm size_t metadata_size; 661316338Smm 662316338Smm if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || 663316338Smm archive_entry_mac_metadata(a->entry, 664316338Smm &metadata_size) == NULL || metadata_size == 0) 665316338Smm#endif 666316338Smm#if ARCHIVE_ACL_LIBRICHACL 667316338Smm /* 668316338Smm * RichACLs are stored in an extended attribute. 669316338Smm * If we intend to extract extended attributes and have this 670316338Smm * attribute we skip extracting libarchive NFSv4 ACLs. 671316338Smm */ 672316338Smm short extract_acls = 1; 673316338Smm if (a->flags & ARCHIVE_EXTRACT_XATTR && ( 674316338Smm archive_entry_acl_types(a->entry) & 675316338Smm ARCHIVE_ENTRY_ACL_TYPE_NFS4)) { 676316338Smm const char *attr_name; 677316338Smm const void *attr_value; 678316338Smm size_t attr_size; 679316338Smm int i = archive_entry_xattr_reset(a->entry); 680316338Smm while (i--) { 681316338Smm archive_entry_xattr_next(a->entry, &attr_name, 682316338Smm &attr_value, &attr_size); 683316338Smm if (attr_name != NULL && attr_value != NULL && 684316338Smm attr_size > 0 && strcmp(attr_name, 685316338Smm "trusted.richacl") == 0) { 686316338Smm extract_acls = 0; 687316338Smm break; 688316338Smm } 689316338Smm } 690316338Smm } 691316338Smm if (extract_acls) 692316338Smm#endif 693316338Smm#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL 694316338Smm { 695316338Smm#endif 696231200Smm if (archive_entry_filetype(a->entry) == AE_IFDIR) 697231200Smm a->deferred |= TODO_ACLS; 698231200Smm else 699231200Smm a->todo |= TODO_ACLS; 700316338Smm#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL 701316338Smm } 702316338Smm#endif 703231200Smm } 704231200Smm if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) { 705231200Smm if (archive_entry_filetype(a->entry) == AE_IFDIR) 706231200Smm a->deferred |= TODO_MAC_METADATA; 707231200Smm else 708231200Smm a->todo |= TODO_MAC_METADATA; 709231200Smm } 710248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) 711248616Smm if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) { 712248616Smm unsigned long set, clear; 713248616Smm archive_entry_fflags(a->entry, &set, &clear); 714248616Smm if ((set & ~clear) & UF_COMPRESSED) { 715248616Smm a->todo |= TODO_HFS_COMPRESSION; 716248616Smm a->decmpfs_block_count = (unsigned)-1; 717248616Smm } 718248616Smm } 719248616Smm if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 && 720248616Smm (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) { 721248616Smm a->todo |= TODO_HFS_COMPRESSION; 722248616Smm a->decmpfs_block_count = (unsigned)-1; 723248616Smm } 724248616Smm { 725248616Smm const char *p; 726248616Smm 727248616Smm /* Check if the current file name is a type of the 728248616Smm * resource fork file. */ 729248616Smm p = strrchr(a->name, '/'); 730248616Smm if (p == NULL) 731248616Smm p = a->name; 732248616Smm else 733248616Smm p++; 734248616Smm if (p[0] == '.' && p[1] == '_') { 735248616Smm /* Do not compress "._XXX" files. */ 736248616Smm a->todo &= ~TODO_HFS_COMPRESSION; 737248616Smm if (a->filesize > 0) 738248616Smm a->todo |= TODO_APPLEDOUBLE; 739248616Smm } 740248616Smm } 741248616Smm#endif 742248616Smm 743316338Smm if (a->flags & ARCHIVE_EXTRACT_XATTR) { 744316338Smm#if ARCHIVE_XATTR_DARWIN 745316338Smm /* 746316338Smm * On MacOS, extended attributes get stored in mac_metadata, 747316338Smm * too. If we intend to extract mac_metadata and it is present 748316338Smm * we skip extracting extended attributes. 749316338Smm */ 750316338Smm size_t metadata_size; 751316338Smm 752316338Smm if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || 753316338Smm archive_entry_mac_metadata(a->entry, 754316338Smm &metadata_size) == NULL || metadata_size == 0) 755316338Smm#endif 756228753Smm a->todo |= TODO_XATTR; 757316338Smm } 758228753Smm if (a->flags & ARCHIVE_EXTRACT_FFLAGS) 759228753Smm a->todo |= TODO_FFLAGS; 760228753Smm if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { 761228753Smm ret = check_symlinks(a); 762228753Smm if (ret != ARCHIVE_OK) 763231200Smm return (ret); 764228753Smm } 765231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX) 766228753Smm /* If path exceeds PATH_MAX, shorten the path. */ 767228753Smm edit_deep_directories(a); 768228753Smm#endif 769228753Smm 770228753Smm ret = restore_entry(a); 771228753Smm 772248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) 773228753Smm /* 774248616Smm * Check if the filesystem the file is restoring on supports 775248616Smm * HFS+ Compression. If not, cancel HFS+ Compression. 776248616Smm */ 777248616Smm if (a->todo | TODO_HFS_COMPRESSION) { 778248616Smm /* 779248616Smm * NOTE: UF_COMPRESSED is ignored even if the filesystem 780248616Smm * supports HFS+ Compression because the file should 781313571Smm * have at least an extended attribute "com.apple.decmpfs" 782248616Smm * before the flag is set to indicate that the file have 783313571Smm * been compressed. If the filesystem does not support 784248616Smm * HFS+ Compression the system call will fail. 785248616Smm */ 786248616Smm if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0) 787248616Smm a->todo &= ~TODO_HFS_COMPRESSION; 788248616Smm } 789248616Smm#endif 790248616Smm 791248616Smm /* 792228753Smm * TODO: There are rumours that some extended attributes must 793228753Smm * be restored before file data is written. If this is true, 794228753Smm * then we either need to write all extended attributes both 795228753Smm * before and after restoring the data, or find some rule for 796228753Smm * determining which must go first and which last. Due to the 797228753Smm * many ways people are using xattrs, this may prove to be an 798228753Smm * intractable problem. 799228753Smm */ 800228753Smm 801228753Smm#ifdef HAVE_FCHDIR 802228753Smm /* If we changed directory above, restore it here. */ 803228753Smm if (a->restore_pwd >= 0) { 804228753Smm r = fchdir(a->restore_pwd); 805228753Smm if (r != 0) { 806309702Smm archive_set_error(&a->archive, errno, 807309702Smm "chdir() failure"); 808228753Smm ret = ARCHIVE_FATAL; 809228753Smm } 810228753Smm close(a->restore_pwd); 811228753Smm a->restore_pwd = -1; 812228753Smm } 813228753Smm#endif 814228753Smm 815228753Smm /* 816228753Smm * Fixup uses the unedited pathname from archive_entry_pathname(), 817228753Smm * because it is relative to the base dir and the edited path 818228753Smm * might be relative to some intermediate dir as a result of the 819228753Smm * deep restore logic. 820228753Smm */ 821228753Smm if (a->deferred & TODO_MODE) { 822228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 823248616Smm if (fe == NULL) 824248616Smm return (ARCHIVE_FATAL); 825228753Smm fe->fixup |= TODO_MODE_BASE; 826228753Smm fe->mode = a->mode; 827228753Smm } 828228753Smm 829228753Smm if ((a->deferred & TODO_TIMES) 830228753Smm && (archive_entry_mtime_is_set(entry) 831228753Smm || archive_entry_atime_is_set(entry))) { 832228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 833248616Smm if (fe == NULL) 834248616Smm return (ARCHIVE_FATAL); 835231200Smm fe->mode = a->mode; 836228753Smm fe->fixup |= TODO_TIMES; 837228753Smm if (archive_entry_atime_is_set(entry)) { 838228753Smm fe->atime = archive_entry_atime(entry); 839228753Smm fe->atime_nanos = archive_entry_atime_nsec(entry); 840228753Smm } else { 841228753Smm /* If atime is unset, use start time. */ 842228753Smm fe->atime = a->start_time; 843228753Smm fe->atime_nanos = 0; 844228753Smm } 845228753Smm if (archive_entry_mtime_is_set(entry)) { 846228753Smm fe->mtime = archive_entry_mtime(entry); 847228753Smm fe->mtime_nanos = archive_entry_mtime_nsec(entry); 848228753Smm } else { 849228753Smm /* If mtime is unset, use start time. */ 850228753Smm fe->mtime = a->start_time; 851228753Smm fe->mtime_nanos = 0; 852228753Smm } 853228753Smm if (archive_entry_birthtime_is_set(entry)) { 854228753Smm fe->birthtime = archive_entry_birthtime(entry); 855309702Smm fe->birthtime_nanos = archive_entry_birthtime_nsec( 856309702Smm entry); 857228753Smm } else { 858228753Smm /* If birthtime is unset, use mtime. */ 859228753Smm fe->birthtime = fe->mtime; 860228753Smm fe->birthtime_nanos = fe->mtime_nanos; 861228753Smm } 862228753Smm } 863228753Smm 864231200Smm if (a->deferred & TODO_ACLS) { 865231200Smm fe = current_fixup(a, archive_entry_pathname(entry)); 866248616Smm if (fe == NULL) 867248616Smm return (ARCHIVE_FATAL); 868238909Smm fe->fixup |= TODO_ACLS; 869231200Smm archive_acl_copy(&fe->acl, archive_entry_acl(entry)); 870231200Smm } 871231200Smm 872231200Smm if (a->deferred & TODO_MAC_METADATA) { 873231200Smm const void *metadata; 874231200Smm size_t metadata_size; 875231200Smm metadata = archive_entry_mac_metadata(a->entry, &metadata_size); 876231200Smm if (metadata != NULL && metadata_size > 0) { 877231200Smm fe = current_fixup(a, archive_entry_pathname(entry)); 878248616Smm if (fe == NULL) 879248616Smm return (ARCHIVE_FATAL); 880231200Smm fe->mac_metadata = malloc(metadata_size); 881231200Smm if (fe->mac_metadata != NULL) { 882309702Smm memcpy(fe->mac_metadata, metadata, 883309702Smm metadata_size); 884231200Smm fe->mac_metadata_size = metadata_size; 885231200Smm fe->fixup |= TODO_MAC_METADATA; 886231200Smm } 887231200Smm } 888231200Smm } 889231200Smm 890228753Smm if (a->deferred & TODO_FFLAGS) { 891228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 892248616Smm if (fe == NULL) 893248616Smm return (ARCHIVE_FATAL); 894228753Smm fe->fixup |= TODO_FFLAGS; 895228753Smm /* TODO: Complete this.. defer fflags from below. */ 896228753Smm } 897228753Smm 898228753Smm /* We've created the object and are ready to pour data into it. */ 899228753Smm if (ret >= ARCHIVE_WARN) 900228753Smm a->archive.state = ARCHIVE_STATE_DATA; 901228753Smm /* 902228753Smm * If it's not open, tell our client not to try writing. 903228753Smm * In particular, dirs, links, etc, don't get written to. 904228753Smm */ 905228753Smm if (a->fd < 0) { 906228753Smm archive_entry_set_size(entry, 0); 907228753Smm a->filesize = 0; 908228753Smm } 909228753Smm 910228753Smm return (ret); 911228753Smm} 912228753Smm 913228753Smmint 914328828Smmarchive_write_disk_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i) 915228753Smm{ 916228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 917231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 918228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file"); 919231200Smm a->skip_file_set = 1; 920228753Smm a->skip_file_dev = d; 921228753Smm a->skip_file_ino = i; 922228753Smm return (ARCHIVE_OK); 923228753Smm} 924228753Smm 925228753Smmstatic ssize_t 926228753Smmwrite_data_block(struct archive_write_disk *a, const char *buff, size_t size) 927228753Smm{ 928228753Smm uint64_t start_size = size; 929228753Smm ssize_t bytes_written = 0; 930228753Smm ssize_t block_size = 0, bytes_to_write; 931228753Smm 932228753Smm if (size == 0) 933228753Smm return (ARCHIVE_OK); 934228753Smm 935228753Smm if (a->filesize == 0 || a->fd < 0) { 936228753Smm archive_set_error(&a->archive, 0, 937228753Smm "Attempt to write to an empty file"); 938228753Smm return (ARCHIVE_WARN); 939228753Smm } 940228753Smm 941228753Smm if (a->flags & ARCHIVE_EXTRACT_SPARSE) { 942228753Smm#if HAVE_STRUCT_STAT_ST_BLKSIZE 943228753Smm int r; 944231200Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 945228753Smm return (r); 946228753Smm block_size = a->pst->st_blksize; 947228753Smm#else 948228753Smm /* XXX TODO XXX Is there a more appropriate choice here ? */ 949228753Smm /* This needn't match the filesystem allocation size. */ 950228753Smm block_size = 16*1024; 951228753Smm#endif 952228753Smm } 953228753Smm 954228753Smm /* If this write would run beyond the file size, truncate it. */ 955231200Smm if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) 956228753Smm start_size = size = (size_t)(a->filesize - a->offset); 957228753Smm 958228753Smm /* Write the data. */ 959228753Smm while (size > 0) { 960228753Smm if (block_size == 0) { 961228753Smm bytes_to_write = size; 962228753Smm } else { 963228753Smm /* We're sparsifying the file. */ 964228753Smm const char *p, *end; 965231200Smm int64_t block_end; 966228753Smm 967228753Smm /* Skip leading zero bytes. */ 968228753Smm for (p = buff, end = buff + size; p < end; ++p) { 969228753Smm if (*p != '\0') 970228753Smm break; 971228753Smm } 972228753Smm a->offset += p - buff; 973228753Smm size -= p - buff; 974228753Smm buff = p; 975228753Smm if (size == 0) 976228753Smm break; 977228753Smm 978228753Smm /* Calculate next block boundary after offset. */ 979228753Smm block_end 980228753Smm = (a->offset / block_size + 1) * block_size; 981228753Smm 982228753Smm /* If the adjusted write would cross block boundary, 983228753Smm * truncate it to the block boundary. */ 984228753Smm bytes_to_write = size; 985228753Smm if (a->offset + bytes_to_write > block_end) 986228753Smm bytes_to_write = block_end - a->offset; 987228753Smm } 988228753Smm /* Seek if necessary to the specified offset. */ 989228753Smm if (a->offset != a->fd_offset) { 990228753Smm if (lseek(a->fd, a->offset, SEEK_SET) < 0) { 991228753Smm archive_set_error(&a->archive, errno, 992228753Smm "Seek failed"); 993228753Smm return (ARCHIVE_FATAL); 994228753Smm } 995228753Smm a->fd_offset = a->offset; 996231200Smm } 997228753Smm bytes_written = write(a->fd, buff, bytes_to_write); 998228753Smm if (bytes_written < 0) { 999228753Smm archive_set_error(&a->archive, errno, "Write failed"); 1000228753Smm return (ARCHIVE_WARN); 1001228753Smm } 1002228753Smm buff += bytes_written; 1003228753Smm size -= bytes_written; 1004231200Smm a->total_bytes_written += bytes_written; 1005228753Smm a->offset += bytes_written; 1006228753Smm a->fd_offset = a->offset; 1007228753Smm } 1008228753Smm return (start_size - size); 1009228753Smm} 1010228753Smm 1011248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ 1012248616Smm && defined(HAVE_ZLIB_H) 1013248616Smm 1014248616Smm/* 1015248616Smm * Set UF_COMPRESSED file flag. 1016248616Smm * This have to be called after hfs_write_decmpfs() because if the 1017248616Smm * file does not have "com.apple.decmpfs" xattr the flag is ignored. 1018248616Smm */ 1019248616Smmstatic int 1020248616Smmhfs_set_compressed_fflag(struct archive_write_disk *a) 1021248616Smm{ 1022248616Smm int r; 1023248616Smm 1024248616Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 1025248616Smm return (r); 1026248616Smm 1027248616Smm a->st.st_flags |= UF_COMPRESSED; 1028248616Smm if (fchflags(a->fd, a->st.st_flags) != 0) { 1029248616Smm archive_set_error(&a->archive, errno, 1030248616Smm "Failed to set UF_COMPRESSED file flag"); 1031248616Smm return (ARCHIVE_WARN); 1032248616Smm } 1033248616Smm return (ARCHIVE_OK); 1034248616Smm} 1035248616Smm 1036248616Smm/* 1037248616Smm * HFS+ Compression decmpfs 1038248616Smm * 1039248616Smm * +------------------------------+ +0 1040248616Smm * | Magic(LE 4 bytes) | 1041248616Smm * +------------------------------+ 1042248616Smm * | Type(LE 4 bytes) | 1043248616Smm * +------------------------------+ 1044248616Smm * | Uncompressed size(LE 8 bytes)| 1045248616Smm * +------------------------------+ +16 1046248616Smm * | | 1047248616Smm * | Compressed data | 1048248616Smm * | (Placed only if Type == 3) | 1049248616Smm * | | 1050248616Smm * +------------------------------+ +3802 = MAX_DECMPFS_XATTR_SIZE 1051248616Smm * 1052248616Smm * Type is 3: decmpfs has compressed data. 1053248616Smm * Type is 4: Resource Fork has compressed data. 1054248616Smm */ 1055248616Smm/* 1056248616Smm * Write "com.apple.decmpfs" 1057248616Smm */ 1058248616Smmstatic int 1059248616Smmhfs_write_decmpfs(struct archive_write_disk *a) 1060248616Smm{ 1061248616Smm int r; 1062248616Smm uint32_t compression_type; 1063248616Smm 1064248616Smm r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p, 1065248616Smm a->decmpfs_attr_size, 0, 0); 1066248616Smm if (r < 0) { 1067248616Smm archive_set_error(&a->archive, errno, 1068248616Smm "Cannot restore xattr:%s", DECMPFS_XATTR_NAME); 1069248616Smm compression_type = archive_le32dec( 1070248616Smm &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]); 1071248616Smm if (compression_type == CMP_RESOURCE_FORK) 1072248616Smm fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 1073248616Smm XATTR_SHOWCOMPRESSION); 1074248616Smm return (ARCHIVE_WARN); 1075248616Smm } 1076248616Smm return (ARCHIVE_OK); 1077248616Smm} 1078248616Smm 1079248616Smm/* 1080248616Smm * HFS+ Compression Resource Fork 1081248616Smm * 1082248616Smm * +-----------------------------+ 1083248616Smm * | Header(260 bytes) | 1084248616Smm * +-----------------------------+ 1085248616Smm * | Block count(LE 4 bytes) | 1086248616Smm * +-----------------------------+ --+ 1087248616Smm * +-- | Offset (LE 4 bytes) | | 1088248616Smm * | | [distance from Block count] | | Block 0 1089248616Smm * | +-----------------------------+ | 1090248616Smm * | | Compressed size(LE 4 bytes) | | 1091248616Smm * | +-----------------------------+ --+ 1092248616Smm * | | | 1093248616Smm * | | .................. | 1094248616Smm * | | | 1095248616Smm * | +-----------------------------+ --+ 1096248616Smm * | | Offset (LE 4 bytes) | | 1097248616Smm * | +-----------------------------+ | Block (Block count -1) 1098248616Smm * | | Compressed size(LE 4 bytes) | | 1099248616Smm * +-> +-----------------------------+ --+ 1100248616Smm * | Compressed data(n bytes) | Block 0 1101248616Smm * +-----------------------------+ 1102248616Smm * | | 1103248616Smm * | .................. | 1104248616Smm * | | 1105248616Smm * +-----------------------------+ 1106248616Smm * | Compressed data(n bytes) | Block (Block count -1) 1107248616Smm * +-----------------------------+ 1108248616Smm * | Footer(50 bytes) | 1109248616Smm * +-----------------------------+ 1110248616Smm * 1111248616Smm */ 1112248616Smm/* 1113248616Smm * Write the header of "com.apple.ResourceFork" 1114248616Smm */ 1115248616Smmstatic int 1116248616Smmhfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff, 1117248616Smm size_t bytes, uint32_t position) 1118248616Smm{ 1119248616Smm int ret; 1120248616Smm 1121248616Smm ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes, 1122248616Smm position, a->rsrc_xattr_options); 1123248616Smm if (ret < 0) { 1124248616Smm archive_set_error(&a->archive, errno, 1125248616Smm "Cannot restore xattr: %s at %u pos %u bytes", 1126248616Smm XATTR_RESOURCEFORK_NAME, 1127248616Smm (unsigned)position, 1128248616Smm (unsigned)bytes); 1129248616Smm return (ARCHIVE_WARN); 1130248616Smm } 1131248616Smm a->rsrc_xattr_options &= ~XATTR_CREATE; 1132248616Smm return (ARCHIVE_OK); 1133248616Smm} 1134248616Smm 1135248616Smmstatic int 1136248616Smmhfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed) 1137248616Smm{ 1138248616Smm int ret; 1139248616Smm 1140248616Smm ret = hfs_write_resource_fork(a, a->compressed_buffer, 1141248616Smm bytes_compressed, a->compressed_rsrc_position); 1142248616Smm if (ret == ARCHIVE_OK) 1143248616Smm a->compressed_rsrc_position += bytes_compressed; 1144248616Smm return (ret); 1145248616Smm} 1146248616Smm 1147248616Smmstatic int 1148248616Smmhfs_write_resource_fork_header(struct archive_write_disk *a) 1149248616Smm{ 1150248616Smm unsigned char *buff; 1151248616Smm uint32_t rsrc_bytes; 1152248616Smm uint32_t rsrc_header_bytes; 1153248616Smm 1154248616Smm /* 1155248616Smm * Write resource fork header + block info. 1156248616Smm */ 1157248616Smm buff = a->resource_fork; 1158248616Smm rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE; 1159248616Smm rsrc_header_bytes = 1160248616Smm RSRC_H_SIZE + /* Header base size. */ 1161248616Smm 4 + /* Block count. */ 1162248616Smm (a->decmpfs_block_count * 8);/* Block info */ 1163248616Smm archive_be32enc(buff, 0x100); 1164248616Smm archive_be32enc(buff + 4, rsrc_bytes); 1165248616Smm archive_be32enc(buff + 8, rsrc_bytes - 256); 1166248616Smm archive_be32enc(buff + 12, 0x32); 1167248616Smm memset(buff + 16, 0, 240); 1168248616Smm archive_be32enc(buff + 256, rsrc_bytes - 260); 1169248616Smm return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0); 1170248616Smm} 1171248616Smm 1172248616Smmstatic size_t 1173248616Smmhfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size) 1174248616Smm{ 1175248616Smm static const char rsrc_footer[RSRC_F_SIZE] = { 1176248616Smm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1177248616Smm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1178248616Smm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1179248616Smm 0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c', 'm', 1180248616Smm 'p', 'f', 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 1181248616Smm 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1182248616Smm 0x00, 0x00 1183248616Smm }; 1184248616Smm if (buff_size < sizeof(rsrc_footer)) 1185248616Smm return (0); 1186248616Smm memcpy(buff, rsrc_footer, sizeof(rsrc_footer)); 1187248616Smm return (sizeof(rsrc_footer)); 1188248616Smm} 1189248616Smm 1190248616Smmstatic int 1191248616Smmhfs_reset_compressor(struct archive_write_disk *a) 1192248616Smm{ 1193248616Smm int ret; 1194248616Smm 1195248616Smm if (a->stream_valid) 1196248616Smm ret = deflateReset(&a->stream); 1197248616Smm else 1198248616Smm ret = deflateInit(&a->stream, a->decmpfs_compression_level); 1199248616Smm 1200248616Smm if (ret != Z_OK) { 1201248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1202248616Smm "Failed to initialize compressor"); 1203248616Smm return (ARCHIVE_FATAL); 1204248616Smm } else 1205248616Smm a->stream_valid = 1; 1206248616Smm 1207248616Smm return (ARCHIVE_OK); 1208248616Smm} 1209248616Smm 1210248616Smmstatic int 1211248616Smmhfs_decompress(struct archive_write_disk *a) 1212248616Smm{ 1213248616Smm uint32_t *block_info; 1214248616Smm unsigned int block_count; 1215248616Smm uint32_t data_pos, data_size; 1216248616Smm ssize_t r; 1217248616Smm ssize_t bytes_written, bytes_to_write; 1218248616Smm unsigned char *b; 1219248616Smm 1220248616Smm block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE); 1221248616Smm block_count = archive_le32dec(block_info++); 1222248616Smm while (block_count--) { 1223248616Smm data_pos = RSRC_H_SIZE + archive_le32dec(block_info++); 1224248616Smm data_size = archive_le32dec(block_info++); 1225248616Smm r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME, 1226248616Smm a->compressed_buffer, data_size, data_pos, 0); 1227248616Smm if (r != data_size) { 1228248616Smm archive_set_error(&a->archive, 1229248616Smm (r < 0)?errno:ARCHIVE_ERRNO_MISC, 1230248616Smm "Failed to read resource fork"); 1231248616Smm return (ARCHIVE_WARN); 1232248616Smm } 1233248616Smm if (a->compressed_buffer[0] == 0xff) { 1234248616Smm bytes_to_write = data_size -1; 1235248616Smm b = a->compressed_buffer + 1; 1236248616Smm } else { 1237248616Smm uLong dest_len = MAX_DECMPFS_BLOCK_SIZE; 1238248616Smm int zr; 1239248616Smm 1240248616Smm zr = uncompress((Bytef *)a->uncompressed_buffer, 1241248616Smm &dest_len, a->compressed_buffer, data_size); 1242248616Smm if (zr != Z_OK) { 1243248616Smm archive_set_error(&a->archive, 1244248616Smm ARCHIVE_ERRNO_MISC, 1245248616Smm "Failed to decompress resource fork"); 1246248616Smm return (ARCHIVE_WARN); 1247248616Smm } 1248248616Smm bytes_to_write = dest_len; 1249248616Smm b = (unsigned char *)a->uncompressed_buffer; 1250248616Smm } 1251248616Smm do { 1252248616Smm bytes_written = write(a->fd, b, bytes_to_write); 1253248616Smm if (bytes_written < 0) { 1254248616Smm archive_set_error(&a->archive, errno, 1255248616Smm "Write failed"); 1256248616Smm return (ARCHIVE_WARN); 1257248616Smm } 1258248616Smm bytes_to_write -= bytes_written; 1259248616Smm b += bytes_written; 1260248616Smm } while (bytes_to_write > 0); 1261248616Smm } 1262248616Smm r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0); 1263248616Smm if (r == -1) { 1264248616Smm archive_set_error(&a->archive, errno, 1265248616Smm "Failed to remove resource fork"); 1266248616Smm return (ARCHIVE_WARN); 1267248616Smm } 1268248616Smm return (ARCHIVE_OK); 1269248616Smm} 1270248616Smm 1271248616Smmstatic int 1272248616Smmhfs_drive_compressor(struct archive_write_disk *a, const char *buff, 1273248616Smm size_t size) 1274248616Smm{ 1275248616Smm unsigned char *buffer_compressed; 1276248616Smm size_t bytes_compressed; 1277248616Smm size_t bytes_used; 1278248616Smm int ret; 1279248616Smm 1280248616Smm ret = hfs_reset_compressor(a); 1281248616Smm if (ret != ARCHIVE_OK) 1282248616Smm return (ret); 1283248616Smm 1284248616Smm if (a->compressed_buffer == NULL) { 1285248616Smm size_t block_size; 1286248616Smm 1287248616Smm block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE + 1288248616Smm + compressBound(MAX_DECMPFS_BLOCK_SIZE); 1289248616Smm a->compressed_buffer = malloc(block_size); 1290248616Smm if (a->compressed_buffer == NULL) { 1291248616Smm archive_set_error(&a->archive, ENOMEM, 1292248616Smm "Can't allocate memory for Resource Fork"); 1293248616Smm return (ARCHIVE_FATAL); 1294248616Smm } 1295248616Smm a->compressed_buffer_size = block_size; 1296248616Smm a->compressed_buffer_remaining = block_size; 1297248616Smm } 1298248616Smm 1299248616Smm buffer_compressed = a->compressed_buffer + 1300248616Smm a->compressed_buffer_size - a->compressed_buffer_remaining; 1301248616Smm a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff; 1302248616Smm a->stream.avail_in = size; 1303248616Smm a->stream.next_out = buffer_compressed; 1304248616Smm a->stream.avail_out = a->compressed_buffer_remaining; 1305248616Smm do { 1306248616Smm ret = deflate(&a->stream, Z_FINISH); 1307248616Smm switch (ret) { 1308248616Smm case Z_OK: 1309248616Smm case Z_STREAM_END: 1310248616Smm break; 1311248616Smm default: 1312248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1313248616Smm "Failed to compress data"); 1314248616Smm return (ARCHIVE_FAILED); 1315248616Smm } 1316248616Smm } while (ret == Z_OK); 1317248616Smm bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out; 1318248616Smm 1319248616Smm /* 1320248616Smm * If the compressed size is larger than the original size, 1321248616Smm * throw away compressed data, use uncompressed data instead. 1322248616Smm */ 1323248616Smm if (bytes_compressed > size) { 1324248616Smm buffer_compressed[0] = 0xFF;/* uncompressed marker. */ 1325248616Smm memcpy(buffer_compressed + 1, buff, size); 1326248616Smm bytes_compressed = size + 1; 1327248616Smm } 1328248616Smm a->compressed_buffer_remaining -= bytes_compressed; 1329248616Smm 1330248616Smm /* 1331248616Smm * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE 1332248616Smm * and the block count in the file is only one, store compressed 1333248616Smm * data to decmpfs xattr instead of the resource fork. 1334248616Smm */ 1335248616Smm if (a->decmpfs_block_count == 1 && 1336248616Smm (a->decmpfs_attr_size + bytes_compressed) 1337248616Smm <= MAX_DECMPFS_XATTR_SIZE) { 1338248616Smm archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], 1339248616Smm CMP_XATTR); 1340248616Smm memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE, 1341248616Smm buffer_compressed, bytes_compressed); 1342248616Smm a->decmpfs_attr_size += bytes_compressed; 1343248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size; 1344248616Smm /* 1345248616Smm * Finish HFS+ Compression. 1346248616Smm * - Write the decmpfs xattr. 1347248616Smm * - Set the UF_COMPRESSED file flag. 1348248616Smm */ 1349248616Smm ret = hfs_write_decmpfs(a); 1350248616Smm if (ret == ARCHIVE_OK) 1351248616Smm ret = hfs_set_compressed_fflag(a); 1352248616Smm return (ret); 1353248616Smm } 1354248616Smm 1355248616Smm /* Update block info. */ 1356248616Smm archive_le32enc(a->decmpfs_block_info++, 1357248616Smm a->compressed_rsrc_position_v - RSRC_H_SIZE); 1358248616Smm archive_le32enc(a->decmpfs_block_info++, bytes_compressed); 1359248616Smm a->compressed_rsrc_position_v += bytes_compressed; 1360248616Smm 1361248616Smm /* 1362248616Smm * Write the compressed data to the resource fork. 1363248616Smm */ 1364248616Smm bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining; 1365248616Smm while (bytes_used >= COMPRESSED_W_SIZE) { 1366248616Smm ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE); 1367248616Smm if (ret != ARCHIVE_OK) 1368248616Smm return (ret); 1369248616Smm bytes_used -= COMPRESSED_W_SIZE; 1370248616Smm if (bytes_used > COMPRESSED_W_SIZE) 1371248616Smm memmove(a->compressed_buffer, 1372248616Smm a->compressed_buffer + COMPRESSED_W_SIZE, 1373248616Smm bytes_used); 1374248616Smm else 1375248616Smm memcpy(a->compressed_buffer, 1376248616Smm a->compressed_buffer + COMPRESSED_W_SIZE, 1377248616Smm bytes_used); 1378248616Smm } 1379248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used; 1380248616Smm 1381248616Smm /* 1382248616Smm * If the current block is the last block, write the remaining 1383248616Smm * compressed data and the resource fork footer. 1384248616Smm */ 1385248616Smm if (a->file_remaining_bytes == 0) { 1386248616Smm size_t rsrc_size; 1387248616Smm int64_t bk; 1388248616Smm 1389248616Smm /* Append the resource footer. */ 1390248616Smm rsrc_size = hfs_set_resource_fork_footer( 1391248616Smm a->compressed_buffer + bytes_used, 1392248616Smm a->compressed_buffer_remaining); 1393248616Smm ret = hfs_write_compressed_data(a, bytes_used + rsrc_size); 1394248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size; 1395248616Smm 1396313571Smm /* If the compressed size is not enough smaller than 1397248616Smm * the uncompressed size. cancel HFS+ compression. 1398248616Smm * TODO: study a behavior of ditto utility and improve 1399248616Smm * the condition to fall back into no HFS+ compression. */ 1400248616Smm bk = HFS_BLOCKS(a->compressed_rsrc_position); 1401248616Smm bk += bk >> 7; 1402248616Smm if (bk > HFS_BLOCKS(a->filesize)) 1403248616Smm return hfs_decompress(a); 1404248616Smm /* 1405248616Smm * Write the resourcefork header. 1406248616Smm */ 1407248616Smm if (ret == ARCHIVE_OK) 1408248616Smm ret = hfs_write_resource_fork_header(a); 1409248616Smm /* 1410248616Smm * Finish HFS+ Compression. 1411248616Smm * - Write the decmpfs xattr. 1412248616Smm * - Set the UF_COMPRESSED file flag. 1413248616Smm */ 1414248616Smm if (ret == ARCHIVE_OK) 1415248616Smm ret = hfs_write_decmpfs(a); 1416248616Smm if (ret == ARCHIVE_OK) 1417248616Smm ret = hfs_set_compressed_fflag(a); 1418248616Smm } 1419248616Smm return (ret); 1420248616Smm} 1421248616Smm 1422228753Smmstatic ssize_t 1423248616Smmhfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff, 1424248616Smm size_t size) 1425248616Smm{ 1426248616Smm const char *buffer_to_write; 1427248616Smm size_t bytes_to_write; 1428248616Smm int ret; 1429248616Smm 1430248616Smm if (a->decmpfs_block_count == (unsigned)-1) { 1431248616Smm void *new_block; 1432248616Smm size_t new_size; 1433248616Smm unsigned int block_count; 1434248616Smm 1435248616Smm if (a->decmpfs_header_p == NULL) { 1436248616Smm new_block = malloc(MAX_DECMPFS_XATTR_SIZE 1437248616Smm + sizeof(uint32_t)); 1438248616Smm if (new_block == NULL) { 1439248616Smm archive_set_error(&a->archive, ENOMEM, 1440248616Smm "Can't allocate memory for decmpfs"); 1441248616Smm return (ARCHIVE_FATAL); 1442248616Smm } 1443248616Smm a->decmpfs_header_p = new_block; 1444248616Smm } 1445248616Smm a->decmpfs_attr_size = DECMPFS_HEADER_SIZE; 1446248616Smm archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC], 1447248616Smm DECMPFS_MAGIC); 1448248616Smm archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], 1449248616Smm CMP_RESOURCE_FORK); 1450248616Smm archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE], 1451248616Smm a->filesize); 1452248616Smm 1453248616Smm /* Calculate a block count of the file. */ 1454248616Smm block_count = 1455248616Smm (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) / 1456248616Smm MAX_DECMPFS_BLOCK_SIZE; 1457248616Smm /* 1458248616Smm * Allocate buffer for resource fork. 1459248616Smm * Set up related pointers; 1460248616Smm */ 1461248616Smm new_size = 1462248616Smm RSRC_H_SIZE + /* header */ 1463248616Smm 4 + /* Block count */ 1464248616Smm (block_count * sizeof(uint32_t) * 2) + 1465248616Smm RSRC_F_SIZE; /* footer */ 1466248616Smm if (new_size > a->resource_fork_allocated_size) { 1467248616Smm new_block = realloc(a->resource_fork, new_size); 1468248616Smm if (new_block == NULL) { 1469248616Smm archive_set_error(&a->archive, ENOMEM, 1470248616Smm "Can't allocate memory for ResourceFork"); 1471248616Smm return (ARCHIVE_FATAL); 1472248616Smm } 1473248616Smm a->resource_fork_allocated_size = new_size; 1474248616Smm a->resource_fork = new_block; 1475248616Smm } 1476248616Smm 1477248616Smm /* Allocate uncompressed buffer */ 1478248616Smm if (a->uncompressed_buffer == NULL) { 1479248616Smm new_block = malloc(MAX_DECMPFS_BLOCK_SIZE); 1480248616Smm if (new_block == NULL) { 1481248616Smm archive_set_error(&a->archive, ENOMEM, 1482248616Smm "Can't allocate memory for decmpfs"); 1483248616Smm return (ARCHIVE_FATAL); 1484248616Smm } 1485248616Smm a->uncompressed_buffer = new_block; 1486248616Smm } 1487248616Smm a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; 1488248616Smm a->file_remaining_bytes = a->filesize; 1489248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size; 1490248616Smm 1491248616Smm /* 1492248616Smm * Set up a resource fork. 1493248616Smm */ 1494248616Smm a->rsrc_xattr_options = XATTR_CREATE; 1495248616Smm /* Get the position where we are going to set a bunch 1496248616Smm * of block info. */ 1497248616Smm a->decmpfs_block_info = 1498248616Smm (uint32_t *)(a->resource_fork + RSRC_H_SIZE); 1499248616Smm /* Set the block count to the resource fork. */ 1500248616Smm archive_le32enc(a->decmpfs_block_info++, block_count); 1501313571Smm /* Get the position where we are going to set compressed 1502248616Smm * data. */ 1503248616Smm a->compressed_rsrc_position = 1504248616Smm RSRC_H_SIZE + 4 + (block_count * 8); 1505248616Smm a->compressed_rsrc_position_v = a->compressed_rsrc_position; 1506248616Smm a->decmpfs_block_count = block_count; 1507248616Smm } 1508248616Smm 1509248616Smm /* Ignore redundant bytes. */ 1510248616Smm if (a->file_remaining_bytes == 0) 1511248616Smm return ((ssize_t)size); 1512248616Smm 1513248616Smm /* Do not overrun a block size. */ 1514248616Smm if (size > a->block_remaining_bytes) 1515248616Smm bytes_to_write = a->block_remaining_bytes; 1516248616Smm else 1517248616Smm bytes_to_write = size; 1518248616Smm /* Do not overrun the file size. */ 1519248616Smm if (bytes_to_write > a->file_remaining_bytes) 1520248616Smm bytes_to_write = a->file_remaining_bytes; 1521248616Smm 1522248616Smm /* For efficiency, if a copy length is full of the uncompressed 1523248616Smm * buffer size, do not copy writing data to it. */ 1524248616Smm if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE) 1525248616Smm buffer_to_write = buff; 1526248616Smm else { 1527248616Smm memcpy(a->uncompressed_buffer + 1528248616Smm MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes, 1529248616Smm buff, bytes_to_write); 1530248616Smm buffer_to_write = a->uncompressed_buffer; 1531248616Smm } 1532248616Smm a->block_remaining_bytes -= bytes_to_write; 1533248616Smm a->file_remaining_bytes -= bytes_to_write; 1534248616Smm 1535248616Smm if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) { 1536248616Smm ret = hfs_drive_compressor(a, buffer_to_write, 1537248616Smm MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes); 1538248616Smm if (ret < 0) 1539248616Smm return (ret); 1540248616Smm a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; 1541248616Smm } 1542248616Smm /* Ignore redundant bytes. */ 1543248616Smm if (a->file_remaining_bytes == 0) 1544248616Smm return ((ssize_t)size); 1545248616Smm return (bytes_to_write); 1546248616Smm} 1547248616Smm 1548248616Smmstatic ssize_t 1549248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff, 1550248616Smm size_t size) 1551248616Smm{ 1552248616Smm uint64_t start_size = size; 1553248616Smm ssize_t bytes_written = 0; 1554248616Smm ssize_t bytes_to_write; 1555248616Smm 1556248616Smm if (size == 0) 1557248616Smm return (ARCHIVE_OK); 1558248616Smm 1559248616Smm if (a->filesize == 0 || a->fd < 0) { 1560248616Smm archive_set_error(&a->archive, 0, 1561248616Smm "Attempt to write to an empty file"); 1562248616Smm return (ARCHIVE_WARN); 1563248616Smm } 1564248616Smm 1565248616Smm /* If this write would run beyond the file size, truncate it. */ 1566248616Smm if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) 1567248616Smm start_size = size = (size_t)(a->filesize - a->offset); 1568248616Smm 1569248616Smm /* Write the data. */ 1570248616Smm while (size > 0) { 1571248616Smm bytes_to_write = size; 1572248616Smm /* Seek if necessary to the specified offset. */ 1573248616Smm if (a->offset < a->fd_offset) { 1574313571Smm /* Can't support backward move. */ 1575248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1576248616Smm "Seek failed"); 1577248616Smm return (ARCHIVE_FATAL); 1578248616Smm } else if (a->offset > a->fd_offset) { 1579248616Smm int64_t skip = a->offset - a->fd_offset; 1580248616Smm char nullblock[1024]; 1581248616Smm 1582248616Smm memset(nullblock, 0, sizeof(nullblock)); 1583248616Smm while (skip > 0) { 1584248616Smm if (skip > (int64_t)sizeof(nullblock)) 1585248616Smm bytes_written = hfs_write_decmpfs_block( 1586248616Smm a, nullblock, sizeof(nullblock)); 1587248616Smm else 1588248616Smm bytes_written = hfs_write_decmpfs_block( 1589248616Smm a, nullblock, skip); 1590248616Smm if (bytes_written < 0) { 1591248616Smm archive_set_error(&a->archive, errno, 1592248616Smm "Write failed"); 1593248616Smm return (ARCHIVE_WARN); 1594248616Smm } 1595248616Smm skip -= bytes_written; 1596248616Smm } 1597248616Smm 1598248616Smm a->fd_offset = a->offset; 1599248616Smm } 1600248616Smm bytes_written = 1601248616Smm hfs_write_decmpfs_block(a, buff, bytes_to_write); 1602248616Smm if (bytes_written < 0) 1603248616Smm return (bytes_written); 1604248616Smm buff += bytes_written; 1605248616Smm size -= bytes_written; 1606248616Smm a->total_bytes_written += bytes_written; 1607248616Smm a->offset += bytes_written; 1608248616Smm a->fd_offset = a->offset; 1609248616Smm } 1610248616Smm return (start_size - size); 1611248616Smm} 1612248616Smm#else 1613248616Smmstatic ssize_t 1614248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff, 1615248616Smm size_t size) 1616248616Smm{ 1617248616Smm return (write_data_block(a, buff, size)); 1618248616Smm} 1619248616Smm#endif 1620248616Smm 1621248616Smmstatic ssize_t 1622231200Smm_archive_write_disk_data_block(struct archive *_a, 1623231200Smm const void *buff, size_t size, int64_t offset) 1624228753Smm{ 1625228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1626228753Smm ssize_t r; 1627228753Smm 1628231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1629231200Smm ARCHIVE_STATE_DATA, "archive_write_data_block"); 1630228753Smm 1631228753Smm a->offset = offset; 1632248616Smm if (a->todo & TODO_HFS_COMPRESSION) 1633248616Smm r = hfs_write_data_block(a, buff, size); 1634248616Smm else 1635248616Smm r = write_data_block(a, buff, size); 1636228753Smm if (r < ARCHIVE_OK) 1637228753Smm return (r); 1638228753Smm if ((size_t)r < size) { 1639228753Smm archive_set_error(&a->archive, 0, 1640309702Smm "Too much data: Truncating file at %ju bytes", 1641309702Smm (uintmax_t)a->filesize); 1642228753Smm return (ARCHIVE_WARN); 1643228753Smm } 1644302001Smm#if ARCHIVE_VERSION_NUMBER < 3999000 1645228753Smm return (ARCHIVE_OK); 1646302001Smm#else 1647302001Smm return (size); 1648302001Smm#endif 1649228753Smm} 1650228753Smm 1651228753Smmstatic ssize_t 1652231200Smm_archive_write_disk_data(struct archive *_a, const void *buff, size_t size) 1653228753Smm{ 1654228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1655228753Smm 1656231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1657228753Smm ARCHIVE_STATE_DATA, "archive_write_data"); 1658228753Smm 1659248616Smm if (a->todo & TODO_HFS_COMPRESSION) 1660248616Smm return (hfs_write_data_block(a, buff, size)); 1661228753Smm return (write_data_block(a, buff, size)); 1662228753Smm} 1663228753Smm 1664228753Smmstatic int 1665231200Smm_archive_write_disk_finish_entry(struct archive *_a) 1666228753Smm{ 1667228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1668228753Smm int ret = ARCHIVE_OK; 1669228753Smm 1670231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1671228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1672228753Smm "archive_write_finish_entry"); 1673228753Smm if (a->archive.state & ARCHIVE_STATE_HEADER) 1674228753Smm return (ARCHIVE_OK); 1675228753Smm archive_clear_error(&a->archive); 1676228753Smm 1677228753Smm /* Pad or truncate file to the right size. */ 1678228753Smm if (a->fd < 0) { 1679228753Smm /* There's no file. */ 1680228753Smm } else if (a->filesize < 0) { 1681228753Smm /* File size is unknown, so we can't set the size. */ 1682228753Smm } else if (a->fd_offset == a->filesize) { 1683228753Smm /* Last write ended at exactly the filesize; we're done. */ 1684228753Smm /* Hopefully, this is the common case. */ 1685248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) 1686248616Smm } else if (a->todo & TODO_HFS_COMPRESSION) { 1687248616Smm char null_d[1024]; 1688248616Smm ssize_t r; 1689248616Smm 1690248616Smm if (a->file_remaining_bytes) 1691248616Smm memset(null_d, 0, sizeof(null_d)); 1692248616Smm while (a->file_remaining_bytes) { 1693248616Smm if (a->file_remaining_bytes > sizeof(null_d)) 1694248616Smm r = hfs_write_data_block( 1695248616Smm a, null_d, sizeof(null_d)); 1696248616Smm else 1697248616Smm r = hfs_write_data_block( 1698248616Smm a, null_d, a->file_remaining_bytes); 1699248616Smm if (r < 0) 1700248616Smm return ((int)r); 1701248616Smm } 1702248616Smm#endif 1703228753Smm } else { 1704228753Smm#if HAVE_FTRUNCATE 1705228753Smm if (ftruncate(a->fd, a->filesize) == -1 && 1706228753Smm a->filesize == 0) { 1707228753Smm archive_set_error(&a->archive, errno, 1708228753Smm "File size could not be restored"); 1709228753Smm return (ARCHIVE_FAILED); 1710228753Smm } 1711228753Smm#endif 1712228753Smm /* 1713228753Smm * Not all platforms implement the XSI option to 1714228753Smm * extend files via ftruncate. Stat() the file again 1715228753Smm * to see what happened. 1716228753Smm */ 1717228753Smm a->pst = NULL; 1718231200Smm if ((ret = lazy_stat(a)) != ARCHIVE_OK) 1719228753Smm return (ret); 1720228753Smm /* We can use lseek()/write() to extend the file if 1721228753Smm * ftruncate didn't work or isn't available. */ 1722228753Smm if (a->st.st_size < a->filesize) { 1723228753Smm const char nul = '\0'; 1724228753Smm if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) { 1725228753Smm archive_set_error(&a->archive, errno, 1726228753Smm "Seek failed"); 1727228753Smm return (ARCHIVE_FATAL); 1728228753Smm } 1729228753Smm if (write(a->fd, &nul, 1) < 0) { 1730228753Smm archive_set_error(&a->archive, errno, 1731228753Smm "Write to restore size failed"); 1732228753Smm return (ARCHIVE_FATAL); 1733228753Smm } 1734228753Smm a->pst = NULL; 1735228753Smm } 1736228753Smm } 1737228753Smm 1738228753Smm /* Restore metadata. */ 1739228753Smm 1740228753Smm /* 1741248616Smm * This is specific to Mac OS X. 1742248616Smm * If the current file is an AppleDouble file, it should be 1743248616Smm * linked with the data fork file and remove it. 1744248616Smm */ 1745248616Smm if (a->todo & TODO_APPLEDOUBLE) { 1746248616Smm int r2 = fixup_appledouble(a, a->name); 1747248616Smm if (r2 == ARCHIVE_EOF) { 1748248616Smm /* The current file has been successfully linked 1749248616Smm * with the data fork file and removed. So there 1750248616Smm * is nothing to do on the current file. */ 1751248616Smm goto finish_metadata; 1752248616Smm } 1753248616Smm if (r2 < ret) ret = r2; 1754248616Smm } 1755248616Smm 1756248616Smm /* 1757228753Smm * Look up the "real" UID only if we're going to need it. 1758228753Smm * TODO: the TODO_SGID condition can be dropped here, can't it? 1759228753Smm */ 1760228753Smm if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { 1761231200Smm a->uid = archive_write_disk_uid(&a->archive, 1762228753Smm archive_entry_uname(a->entry), 1763228753Smm archive_entry_uid(a->entry)); 1764228753Smm } 1765228753Smm /* Look up the "real" GID only if we're going to need it. */ 1766228753Smm /* TODO: the TODO_SUID condition can be dropped here, can't it? */ 1767228753Smm if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { 1768231200Smm a->gid = archive_write_disk_gid(&a->archive, 1769228753Smm archive_entry_gname(a->entry), 1770228753Smm archive_entry_gid(a->entry)); 1771228753Smm } 1772231200Smm 1773228753Smm /* 1774231200Smm * Restore ownership before set_mode tries to restore suid/sgid 1775228753Smm * bits. If we set the owner, we know what it is and can skip 1776228753Smm * a stat() call to examine the ownership of the file on disk. 1777228753Smm */ 1778248616Smm if (a->todo & TODO_OWNER) { 1779248616Smm int r2 = set_ownership(a); 1780248616Smm if (r2 < ret) ret = r2; 1781248616Smm } 1782231200Smm 1783231200Smm /* 1784231200Smm * set_mode must precede ACLs on systems such as Solaris and 1785231200Smm * FreeBSD where setting the mode implicitly clears extended ACLs 1786231200Smm */ 1787228753Smm if (a->todo & TODO_MODE) { 1788228753Smm int r2 = set_mode(a, a->mode); 1789228753Smm if (r2 < ret) ret = r2; 1790228753Smm } 1791228753Smm 1792228753Smm /* 1793228753Smm * Security-related extended attributes (such as 1794228753Smm * security.capability on Linux) have to be restored last, 1795228753Smm * since they're implicitly removed by other file changes. 1796228753Smm */ 1797228753Smm if (a->todo & TODO_XATTR) { 1798228753Smm int r2 = set_xattrs(a); 1799228753Smm if (r2 < ret) ret = r2; 1800228753Smm } 1801228753Smm 1802228753Smm /* 1803228753Smm * Some flags prevent file modification; they must be restored after 1804228753Smm * file contents are written. 1805228753Smm */ 1806228753Smm if (a->todo & TODO_FFLAGS) { 1807228753Smm int r2 = set_fflags(a); 1808228753Smm if (r2 < ret) ret = r2; 1809228753Smm } 1810231200Smm 1811228753Smm /* 1812231200Smm * Time must follow most other metadata; 1813228753Smm * otherwise atime will get changed. 1814228753Smm */ 1815228753Smm if (a->todo & TODO_TIMES) { 1816231200Smm int r2 = set_times_from_entry(a); 1817228753Smm if (r2 < ret) ret = r2; 1818228753Smm } 1819228753Smm 1820231200Smm /* 1821231200Smm * Mac extended metadata includes ACLs. 1822231200Smm */ 1823231200Smm if (a->todo & TODO_MAC_METADATA) { 1824231200Smm const void *metadata; 1825231200Smm size_t metadata_size; 1826231200Smm metadata = archive_entry_mac_metadata(a->entry, &metadata_size); 1827231200Smm if (metadata != NULL && metadata_size > 0) { 1828248616Smm int r2 = set_mac_metadata(a, archive_entry_pathname( 1829248616Smm a->entry), metadata, metadata_size); 1830231200Smm if (r2 < ret) ret = r2; 1831231200Smm } 1832231200Smm } 1833231200Smm 1834231200Smm /* 1835231200Smm * ACLs must be restored after timestamps because there are 1836231200Smm * ACLs that prevent attribute changes (including time). 1837231200Smm */ 1838231200Smm if (a->todo & TODO_ACLS) { 1839313571Smm int r2; 1840313571Smm r2 = archive_write_disk_set_acls(&a->archive, a->fd, 1841313571Smm archive_entry_pathname(a->entry), 1842316338Smm archive_entry_acl(a->entry), 1843316338Smm archive_entry_mode(a->entry)); 1844231200Smm if (r2 < ret) ret = r2; 1845231200Smm } 1846231200Smm 1847248616Smmfinish_metadata: 1848228753Smm /* If there's an fd, we can close it now. */ 1849228753Smm if (a->fd >= 0) { 1850228753Smm close(a->fd); 1851228753Smm a->fd = -1; 1852358090Smm if (a->tmpname) { 1853358090Smm if (rename(a->tmpname, a->name) == -1) { 1854358090Smm archive_set_error(&a->archive, errno, 1855358927Smm "Failed to rename temporary file"); 1856358927Smm ret = ARCHIVE_FAILED; 1857358927Smm unlink(a->tmpname); 1858358090Smm } 1859358090Smm a->tmpname = NULL; 1860358090Smm } 1861228753Smm } 1862228753Smm /* If there's an entry, we can release it now. */ 1863344674Smm archive_entry_free(a->entry); 1864344674Smm a->entry = NULL; 1865228753Smm a->archive.state = ARCHIVE_STATE_HEADER; 1866228753Smm return (ret); 1867228753Smm} 1868228753Smm 1869228753Smmint 1870228753Smmarchive_write_disk_set_group_lookup(struct archive *_a, 1871228753Smm void *private_data, 1872328828Smm la_int64_t (*lookup_gid)(void *private, const char *gname, la_int64_t gid), 1873228753Smm void (*cleanup_gid)(void *private)) 1874228753Smm{ 1875228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1876231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1877228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); 1878228753Smm 1879231200Smm if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) 1880231200Smm (a->cleanup_gid)(a->lookup_gid_data); 1881231200Smm 1882228753Smm a->lookup_gid = lookup_gid; 1883228753Smm a->cleanup_gid = cleanup_gid; 1884228753Smm a->lookup_gid_data = private_data; 1885228753Smm return (ARCHIVE_OK); 1886228753Smm} 1887228753Smm 1888228753Smmint 1889228753Smmarchive_write_disk_set_user_lookup(struct archive *_a, 1890228753Smm void *private_data, 1891231200Smm int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid), 1892228753Smm void (*cleanup_uid)(void *private)) 1893228753Smm{ 1894228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1895231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1896228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); 1897228753Smm 1898231200Smm if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) 1899231200Smm (a->cleanup_uid)(a->lookup_uid_data); 1900231200Smm 1901228753Smm a->lookup_uid = lookup_uid; 1902228753Smm a->cleanup_uid = cleanup_uid; 1903228753Smm a->lookup_uid_data = private_data; 1904228753Smm return (ARCHIVE_OK); 1905228753Smm} 1906228753Smm 1907231200Smmint64_t 1908328828Smmarchive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id) 1909231200Smm{ 1910231200Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1911231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1912231200Smm ARCHIVE_STATE_ANY, "archive_write_disk_gid"); 1913231200Smm if (a->lookup_gid) 1914231200Smm return (a->lookup_gid)(a->lookup_gid_data, name, id); 1915231200Smm return (id); 1916231200Smm} 1917231200Smm 1918231200Smmint64_t 1919328828Smmarchive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id) 1920231200Smm{ 1921238909Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1922238909Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1923238909Smm ARCHIVE_STATE_ANY, "archive_write_disk_uid"); 1924238909Smm if (a->lookup_uid) 1925238909Smm return (a->lookup_uid)(a->lookup_uid_data, name, id); 1926238909Smm return (id); 1927231200Smm} 1928228753Smm 1929228753Smm/* 1930228753Smm * Create a new archive_write_disk object and initialize it with global state. 1931228753Smm */ 1932228753Smmstruct archive * 1933228753Smmarchive_write_disk_new(void) 1934228753Smm{ 1935228753Smm struct archive_write_disk *a; 1936228753Smm 1937311042Smm a = (struct archive_write_disk *)calloc(1, sizeof(*a)); 1938228753Smm if (a == NULL) 1939228753Smm return (NULL); 1940228753Smm a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; 1941228753Smm /* We're ready to write a header immediately. */ 1942228753Smm a->archive.state = ARCHIVE_STATE_HEADER; 1943228753Smm a->archive.vtable = archive_write_disk_vtable(); 1944228753Smm a->start_time = time(NULL); 1945231200Smm /* Query and restore the umask. */ 1946231200Smm umask(a->user_umask = umask(0)); 1947228753Smm#ifdef HAVE_GETEUID 1948228753Smm a->user_uid = geteuid(); 1949228753Smm#endif /* HAVE_GETEUID */ 1950228753Smm if (archive_string_ensure(&a->path_safe, 512) == NULL) { 1951228753Smm free(a); 1952228753Smm return (NULL); 1953228753Smm } 1954248616Smm#ifdef HAVE_ZLIB_H 1955248616Smm a->decmpfs_compression_level = 5; 1956248616Smm#endif 1957228753Smm return (&a->archive); 1958228753Smm} 1959228753Smm 1960228753Smm 1961228753Smm/* 1962228753Smm * If pathname is longer than PATH_MAX, chdir to a suitable 1963228753Smm * intermediate dir and edit the path down to a shorter suffix. Note 1964228753Smm * that this routine never returns an error; if the chdir() attempt 1965228753Smm * fails for any reason, we just go ahead with the long pathname. The 1966228753Smm * object creation is likely to fail, but any error will get handled 1967228753Smm * at that time. 1968228753Smm */ 1969231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX) 1970228753Smmstatic void 1971228753Smmedit_deep_directories(struct archive_write_disk *a) 1972228753Smm{ 1973228753Smm int ret; 1974228753Smm char *tail = a->name; 1975228753Smm 1976228753Smm /* If path is short, avoid the open() below. */ 1977305192Smm if (strlen(tail) < PATH_MAX) 1978228753Smm return; 1979228753Smm 1980228753Smm /* Try to record our starting dir. */ 1981349525Smm a->restore_pwd = la_opendirat(AT_FDCWD, "."); 1982248616Smm __archive_ensure_cloexec_flag(a->restore_pwd); 1983228753Smm if (a->restore_pwd < 0) 1984228753Smm return; 1985228753Smm 1986228753Smm /* As long as the path is too long... */ 1987305192Smm while (strlen(tail) >= PATH_MAX) { 1988228753Smm /* Locate a dir prefix shorter than PATH_MAX. */ 1989228753Smm tail += PATH_MAX - 8; 1990228753Smm while (tail > a->name && *tail != '/') 1991228753Smm tail--; 1992228753Smm /* Exit if we find a too-long path component. */ 1993228753Smm if (tail <= a->name) 1994228753Smm return; 1995228753Smm /* Create the intermediate dir and chdir to it. */ 1996228753Smm *tail = '\0'; /* Terminate dir portion */ 1997228753Smm ret = create_dir(a, a->name); 1998228753Smm if (ret == ARCHIVE_OK && chdir(a->name) != 0) 1999228753Smm ret = ARCHIVE_FAILED; 2000228753Smm *tail = '/'; /* Restore the / we removed. */ 2001228753Smm if (ret != ARCHIVE_OK) 2002228753Smm return; 2003228753Smm tail++; 2004228753Smm /* The chdir() succeeded; we've now shortened the path. */ 2005228753Smm a->name = tail; 2006228753Smm } 2007228753Smm return; 2008228753Smm} 2009228753Smm#endif 2010228753Smm 2011228753Smm/* 2012228753Smm * The main restore function. 2013228753Smm */ 2014228753Smmstatic int 2015228753Smmrestore_entry(struct archive_write_disk *a) 2016228753Smm{ 2017228753Smm int ret = ARCHIVE_OK, en; 2018228753Smm 2019228753Smm if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { 2020228753Smm /* 2021228753Smm * TODO: Fix this. Apparently, there are platforms 2022228753Smm * that still allow root to hose the entire filesystem 2023228753Smm * by unlinking a dir. The S_ISDIR() test above 2024228753Smm * prevents us from using unlink() here if the new 2025228753Smm * object is a dir, but that doesn't mean the old 2026228753Smm * object isn't a dir. 2027228753Smm */ 2028302001Smm if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) 2029302001Smm (void)clear_nochange_fflags(a); 2030228753Smm if (unlink(a->name) == 0) { 2031228753Smm /* We removed it, reset cached stat. */ 2032228753Smm a->pst = NULL; 2033228753Smm } else if (errno == ENOENT) { 2034228753Smm /* File didn't exist, that's just as good. */ 2035228753Smm } else if (rmdir(a->name) == 0) { 2036228753Smm /* It was a dir, but now it's gone. */ 2037228753Smm a->pst = NULL; 2038228753Smm } else { 2039228753Smm /* We tried, but couldn't get rid of it. */ 2040228753Smm archive_set_error(&a->archive, errno, 2041228753Smm "Could not unlink"); 2042228753Smm return(ARCHIVE_FAILED); 2043228753Smm } 2044228753Smm } 2045228753Smm 2046228753Smm /* Try creating it first; if this fails, we'll try to recover. */ 2047228753Smm en = create_filesystem_object(a); 2048228753Smm 2049228753Smm if ((en == ENOTDIR || en == ENOENT) 2050228753Smm && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) { 2051228753Smm /* If the parent dir doesn't exist, try creating it. */ 2052228753Smm create_parent_dir(a, a->name); 2053228753Smm /* Now try to create the object again. */ 2054228753Smm en = create_filesystem_object(a); 2055228753Smm } 2056228753Smm 2057302001Smm if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) { 2058302001Smm archive_set_error(&a->archive, en, 2059302001Smm "Hard-link target '%s' does not exist.", 2060302001Smm archive_entry_hardlink(a->entry)); 2061302001Smm return (ARCHIVE_FAILED); 2062302001Smm } 2063302001Smm 2064228753Smm if ((en == EISDIR || en == EEXIST) 2065228753Smm && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { 2066228753Smm /* If we're not overwriting, we're done. */ 2067328828Smm if (S_ISDIR(a->mode)) { 2068328828Smm /* Don't overwrite any settings on existing directories. */ 2069328828Smm a->todo = 0; 2070328828Smm } 2071231200Smm archive_entry_unset_size(a->entry); 2072231200Smm return (ARCHIVE_OK); 2073228753Smm } 2074228753Smm 2075228753Smm /* 2076228753Smm * Some platforms return EISDIR if you call 2077228753Smm * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some 2078228753Smm * return EEXIST. POSIX is ambiguous, requiring EISDIR 2079228753Smm * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT) 2080228753Smm * on an existing item. 2081228753Smm */ 2082228753Smm if (en == EISDIR) { 2083228753Smm /* A dir is in the way of a non-dir, rmdir it. */ 2084228753Smm if (rmdir(a->name) != 0) { 2085228753Smm archive_set_error(&a->archive, errno, 2086228753Smm "Can't remove already-existing dir"); 2087228753Smm return (ARCHIVE_FAILED); 2088228753Smm } 2089228753Smm a->pst = NULL; 2090228753Smm /* Try again. */ 2091228753Smm en = create_filesystem_object(a); 2092228753Smm } else if (en == EEXIST) { 2093228753Smm /* 2094228753Smm * We know something is in the way, but we don't know what; 2095228753Smm * we need to find out before we go any further. 2096228753Smm */ 2097228753Smm int r = 0; 2098228753Smm /* 2099231200Smm * The SECURE_SYMLINKS logic has already removed a 2100228753Smm * symlink to a dir if the client wants that. So 2101228753Smm * follow the symlink if we're creating a dir. 2102228753Smm */ 2103228753Smm if (S_ISDIR(a->mode)) 2104348608Smm r = la_stat(a->name, &a->st); 2105228753Smm /* 2106228753Smm * If it's not a dir (or it's a broken symlink), 2107228753Smm * then don't follow it. 2108228753Smm */ 2109228753Smm if (r != 0 || !S_ISDIR(a->mode)) 2110228753Smm r = lstat(a->name, &a->st); 2111228753Smm if (r != 0) { 2112228753Smm archive_set_error(&a->archive, errno, 2113228753Smm "Can't stat existing object"); 2114228753Smm return (ARCHIVE_FAILED); 2115228753Smm } 2116228753Smm 2117228753Smm /* 2118228753Smm * NO_OVERWRITE_NEWER doesn't apply to directories. 2119228753Smm */ 2120228753Smm if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) 2121228753Smm && !S_ISDIR(a->st.st_mode)) { 2122228753Smm if (!older(&(a->st), a->entry)) { 2123231200Smm archive_entry_unset_size(a->entry); 2124231200Smm return (ARCHIVE_OK); 2125228753Smm } 2126228753Smm } 2127228753Smm 2128228753Smm /* If it's our archive, we're done. */ 2129231200Smm if (a->skip_file_set && 2130238856Smm a->st.st_dev == (dev_t)a->skip_file_dev && 2131238856Smm a->st.st_ino == (ino_t)a->skip_file_ino) { 2132238856Smm archive_set_error(&a->archive, 0, 2133238856Smm "Refusing to overwrite archive"); 2134228753Smm return (ARCHIVE_FAILED); 2135228753Smm } 2136228753Smm 2137228753Smm if (!S_ISDIR(a->st.st_mode)) { 2138302001Smm if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) 2139302001Smm (void)clear_nochange_fflags(a); 2140358090Smm 2141358090Smm if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) && 2142358090Smm S_ISREG(a->st.st_mode)) { 2143358090Smm /* Use a temporary file to extract */ 2144358927Smm if ((a->fd = la_mktemp(a)) == -1) { 2145358927Smm archive_set_error(&a->archive, errno, 2146358927Smm "Can't create temporary file"); 2147358090Smm return ARCHIVE_FAILED; 2148358927Smm } 2149358090Smm a->pst = NULL; 2150358090Smm en = 0; 2151358090Smm } else { 2152358090Smm /* A non-dir is in the way, unlink it. */ 2153358090Smm if (unlink(a->name) != 0) { 2154358090Smm archive_set_error(&a->archive, errno, 2155358090Smm "Can't unlink already-existing " 2156358090Smm "object"); 2157358090Smm return (ARCHIVE_FAILED); 2158358090Smm } 2159358090Smm a->pst = NULL; 2160358090Smm /* Try again. */ 2161358090Smm en = create_filesystem_object(a); 2162228753Smm } 2163228753Smm } else if (!S_ISDIR(a->mode)) { 2164228753Smm /* A dir is in the way of a non-dir, rmdir it. */ 2165302001Smm if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) 2166302001Smm (void)clear_nochange_fflags(a); 2167228753Smm if (rmdir(a->name) != 0) { 2168228753Smm archive_set_error(&a->archive, errno, 2169238856Smm "Can't replace existing directory with non-directory"); 2170228753Smm return (ARCHIVE_FAILED); 2171228753Smm } 2172228753Smm /* Try again. */ 2173228753Smm en = create_filesystem_object(a); 2174228753Smm } else { 2175228753Smm /* 2176228753Smm * There's a dir in the way of a dir. Don't 2177228753Smm * waste time with rmdir()/mkdir(), just fix 2178228753Smm * up the permissions on the existing dir. 2179228753Smm * Note that we don't change perms on existing 2180228753Smm * dirs unless _EXTRACT_PERM is specified. 2181228753Smm */ 2182228753Smm if ((a->mode != a->st.st_mode) 2183228753Smm && (a->todo & TODO_MODE_FORCE)) 2184228753Smm a->deferred |= (a->todo & TODO_MODE); 2185228753Smm /* Ownership doesn't need deferred fixup. */ 2186228753Smm en = 0; /* Forget the EEXIST. */ 2187228753Smm } 2188228753Smm } 2189228753Smm 2190228753Smm if (en) { 2191228753Smm /* Everything failed; give up here. */ 2192309702Smm if ((&a->archive)->error == NULL) 2193309702Smm archive_set_error(&a->archive, en, "Can't create '%s'", 2194309702Smm a->name); 2195228753Smm return (ARCHIVE_FAILED); 2196228753Smm } 2197228753Smm 2198228753Smm a->pst = NULL; /* Cached stat data no longer valid. */ 2199228753Smm return (ret); 2200228753Smm} 2201228753Smm 2202228753Smm/* 2203228753Smm * Returns 0 if creation succeeds, or else returns errno value from 2204228753Smm * the failed system call. Note: This function should only ever perform 2205228753Smm * a single system call. 2206228753Smm */ 2207228753Smmstatic int 2208228753Smmcreate_filesystem_object(struct archive_write_disk *a) 2209228753Smm{ 2210228753Smm /* Create the entry. */ 2211228753Smm const char *linkname; 2212228753Smm mode_t final_mode, mode; 2213228753Smm int r; 2214306322Smm /* these for check_symlinks_fsobj */ 2215306322Smm char *linkname_copy; /* non-const copy of linkname */ 2216315433Smm struct stat st; 2217306322Smm struct archive_string error_string; 2218306322Smm int error_number; 2219228753Smm 2220228753Smm /* We identify hard/symlinks according to the link names. */ 2221228753Smm /* Since link(2) and symlink(2) don't handle modes, we're done here. */ 2222228753Smm linkname = archive_entry_hardlink(a->entry); 2223228753Smm if (linkname != NULL) { 2224228753Smm#if !HAVE_LINK 2225228753Smm return (EPERM); 2226228753Smm#else 2227306322Smm archive_string_init(&error_string); 2228306322Smm linkname_copy = strdup(linkname); 2229306322Smm if (linkname_copy == NULL) { 2230306322Smm return (EPERM); 2231306322Smm } 2232309702Smm /* 2233309702Smm * TODO: consider using the cleaned-up path as the link 2234309702Smm * target? 2235309702Smm */ 2236309702Smm r = cleanup_pathname_fsobj(linkname_copy, &error_number, 2237309702Smm &error_string, a->flags); 2238306322Smm if (r != ARCHIVE_OK) { 2239309702Smm archive_set_error(&a->archive, error_number, "%s", 2240309702Smm error_string.s); 2241306322Smm free(linkname_copy); 2242313571Smm archive_string_free(&error_string); 2243309702Smm /* 2244309702Smm * EPERM is more appropriate than error_number for our 2245309702Smm * callers 2246309702Smm */ 2247306322Smm return (EPERM); 2248306322Smm } 2249309702Smm r = check_symlinks_fsobj(linkname_copy, &error_number, 2250309702Smm &error_string, a->flags); 2251306322Smm if (r != ARCHIVE_OK) { 2252309702Smm archive_set_error(&a->archive, error_number, "%s", 2253309702Smm error_string.s); 2254306322Smm free(linkname_copy); 2255313571Smm archive_string_free(&error_string); 2256309702Smm /* 2257309702Smm * EPERM is more appropriate than error_number for our 2258309702Smm * callers 2259309702Smm */ 2260306322Smm return (EPERM); 2261306322Smm } 2262306322Smm free(linkname_copy); 2263313571Smm archive_string_free(&error_string); 2264358090Smm /* 2265358090Smm * Unlinking and linking here is really not atomic, 2266358090Smm * but doing it right, would require us to construct 2267358090Smm * an mktemplink() function, and then use rename(2). 2268358090Smm */ 2269358090Smm if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) 2270358090Smm unlink(a->name); 2271228753Smm r = link(linkname, a->name) ? errno : 0; 2272228753Smm /* 2273228753Smm * New cpio and pax formats allow hardlink entries 2274228753Smm * to carry data, so we may have to open the file 2275228753Smm * for hardlink entries. 2276228753Smm * 2277228753Smm * If the hardlink was successfully created and 2278228753Smm * the archive doesn't have carry data for it, 2279231200Smm * consider it to be non-authoritative for meta data. 2280228753Smm * This is consistent with GNU tar and BSD pax. 2281228753Smm * If the hardlink does carry data, let the last 2282228753Smm * archive entry decide ownership. 2283228753Smm */ 2284228753Smm if (r == 0 && a->filesize <= 0) { 2285228753Smm a->todo = 0; 2286228753Smm a->deferred = 0; 2287231200Smm } else if (r == 0 && a->filesize > 0) { 2288315433Smm#ifdef HAVE_LSTAT 2289315433Smm r = lstat(a->name, &st); 2290315433Smm#else 2291348608Smm r = la_stat(a->name, &st); 2292315433Smm#endif 2293315433Smm if (r != 0) 2294228753Smm r = errno; 2295315433Smm else if ((st.st_mode & AE_IFMT) == AE_IFREG) { 2296315433Smm a->fd = open(a->name, O_WRONLY | O_TRUNC | 2297315433Smm O_BINARY | O_CLOEXEC | O_NOFOLLOW); 2298315433Smm __archive_ensure_cloexec_flag(a->fd); 2299315433Smm if (a->fd < 0) 2300315433Smm r = errno; 2301315433Smm } 2302228753Smm } 2303228753Smm return (r); 2304228753Smm#endif 2305228753Smm } 2306228753Smm linkname = archive_entry_symlink(a->entry); 2307228753Smm if (linkname != NULL) { 2308228753Smm#if HAVE_SYMLINK 2309358090Smm /* 2310358090Smm * Unlinking and linking here is really not atomic, 2311358090Smm * but doing it right, would require us to construct 2312358090Smm * an mktempsymlink() function, and then use rename(2). 2313358090Smm */ 2314358090Smm if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) 2315358090Smm unlink(a->name); 2316228753Smm return symlink(linkname, a->name) ? errno : 0; 2317228753Smm#else 2318228753Smm return (EPERM); 2319228753Smm#endif 2320228753Smm } 2321228753Smm 2322228753Smm /* 2323228753Smm * The remaining system calls all set permissions, so let's 2324228753Smm * try to take advantage of that to avoid an extra chmod() 2325228753Smm * call. (Recall that umask is set to zero right now!) 2326228753Smm */ 2327228753Smm 2328228753Smm /* Mode we want for the final restored object (w/o file type bits). */ 2329228753Smm final_mode = a->mode & 07777; 2330228753Smm /* 2331228753Smm * The mode that will actually be restored in this step. Note 2332228753Smm * that SUID, SGID, etc, require additional work to ensure 2333228753Smm * security, so we never restore them at this point. 2334228753Smm */ 2335248616Smm mode = final_mode & 0777 & ~a->user_umask; 2336228753Smm 2337228753Smm switch (a->mode & AE_IFMT) { 2338228753Smm default: 2339228753Smm /* POSIX requires that we fall through here. */ 2340228753Smm /* FALLTHROUGH */ 2341228753Smm case AE_IFREG: 2342358090Smm a->tmpname = NULL; 2343228753Smm a->fd = open(a->name, 2344248616Smm O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode); 2345248616Smm __archive_ensure_cloexec_flag(a->fd); 2346228753Smm r = (a->fd < 0); 2347228753Smm break; 2348228753Smm case AE_IFCHR: 2349228753Smm#ifdef HAVE_MKNOD 2350228753Smm /* Note: we use AE_IFCHR for the case label, and 2351228753Smm * S_IFCHR for the mknod() call. This is correct. */ 2352228753Smm r = mknod(a->name, mode | S_IFCHR, 2353228753Smm archive_entry_rdev(a->entry)); 2354228753Smm break; 2355228753Smm#else 2356228753Smm /* TODO: Find a better way to warn about our inability 2357228753Smm * to restore a char device node. */ 2358228753Smm return (EINVAL); 2359228753Smm#endif /* HAVE_MKNOD */ 2360228753Smm case AE_IFBLK: 2361228753Smm#ifdef HAVE_MKNOD 2362228753Smm r = mknod(a->name, mode | S_IFBLK, 2363228753Smm archive_entry_rdev(a->entry)); 2364228753Smm break; 2365228753Smm#else 2366228753Smm /* TODO: Find a better way to warn about our inability 2367228753Smm * to restore a block device node. */ 2368228753Smm return (EINVAL); 2369228753Smm#endif /* HAVE_MKNOD */ 2370228753Smm case AE_IFDIR: 2371228753Smm mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; 2372228753Smm r = mkdir(a->name, mode); 2373228753Smm if (r == 0) { 2374228753Smm /* Defer setting dir times. */ 2375228753Smm a->deferred |= (a->todo & TODO_TIMES); 2376228753Smm a->todo &= ~TODO_TIMES; 2377228753Smm /* Never use an immediate chmod(). */ 2378228753Smm /* We can't avoid the chmod() entirely if EXTRACT_PERM 2379228753Smm * because of SysV SGID inheritance. */ 2380228753Smm if ((mode != final_mode) 2381228753Smm || (a->flags & ARCHIVE_EXTRACT_PERM)) 2382228753Smm a->deferred |= (a->todo & TODO_MODE); 2383228753Smm a->todo &= ~TODO_MODE; 2384228753Smm } 2385228753Smm break; 2386228753Smm case AE_IFIFO: 2387228753Smm#ifdef HAVE_MKFIFO 2388228753Smm r = mkfifo(a->name, mode); 2389228753Smm break; 2390228753Smm#else 2391228753Smm /* TODO: Find a better way to warn about our inability 2392228753Smm * to restore a fifo. */ 2393228753Smm return (EINVAL); 2394228753Smm#endif /* HAVE_MKFIFO */ 2395228753Smm } 2396228753Smm 2397228753Smm /* All the system calls above set errno on failure. */ 2398228753Smm if (r) 2399228753Smm return (errno); 2400228753Smm 2401228753Smm /* If we managed to set the final mode, we've avoided a chmod(). */ 2402228753Smm if (mode == final_mode) 2403228753Smm a->todo &= ~TODO_MODE; 2404228753Smm return (0); 2405228753Smm} 2406228753Smm 2407228753Smm/* 2408228753Smm * Cleanup function for archive_extract. Mostly, this involves processing 2409228753Smm * the fixup list, which is used to address a number of problems: 2410228753Smm * * Dir permissions might prevent us from restoring a file in that 2411228753Smm * dir, so we restore the dir with minimum 0700 permissions first, 2412228753Smm * then correct the mode at the end. 2413228753Smm * * Similarly, the act of restoring a file touches the directory 2414228753Smm * and changes the timestamp on the dir, so we have to touch-up dir 2415228753Smm * timestamps at the end as well. 2416228753Smm * * Some file flags can interfere with the restore by, for example, 2417228753Smm * preventing the creation of hardlinks to those files. 2418231200Smm * * Mac OS extended metadata includes ACLs, so must be deferred on dirs. 2419228753Smm * 2420228753Smm * Note that tar/cpio do not require that archives be in a particular 2421228753Smm * order; there is no way to know when the last file has been restored 2422228753Smm * within a directory, so there's no way to optimize the memory usage 2423228753Smm * here by fixing up the directory any earlier than the 2424228753Smm * end-of-archive. 2425228753Smm * 2426228753Smm * XXX TODO: Directory ACLs should be restored here, for the same 2427228753Smm * reason we set directory perms here. XXX 2428228753Smm */ 2429228753Smmstatic int 2430231200Smm_archive_write_disk_close(struct archive *_a) 2431228753Smm{ 2432228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 2433228753Smm struct fixup_entry *next, *p; 2434349525Smm int fd, ret; 2435228753Smm 2436231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 2437228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 2438228753Smm "archive_write_disk_close"); 2439231200Smm ret = _archive_write_disk_finish_entry(&a->archive); 2440228753Smm 2441228753Smm /* Sort dir list so directories are fixed up in depth-first order. */ 2442228753Smm p = sort_dir_list(a->fixup_list); 2443228753Smm 2444228753Smm while (p != NULL) { 2445349525Smm fd = -1; 2446228753Smm a->pst = NULL; /* Mark stat cache as out-of-date. */ 2447349525Smm if (p->fixup & 2448349525Smm (TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) { 2449349525Smm fd = open(p->name, 2450349525Smm O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC); 2451349525Smm } 2452228753Smm if (p->fixup & TODO_TIMES) { 2453349525Smm set_times(a, fd, p->mode, p->name, 2454231200Smm p->atime, p->atime_nanos, 2455231200Smm p->birthtime, p->birthtime_nanos, 2456231200Smm p->mtime, p->mtime_nanos, 2457231200Smm p->ctime, p->ctime_nanos); 2458228753Smm } 2459349525Smm if (p->fixup & TODO_MODE_BASE) { 2460349525Smm#ifdef HAVE_FCHMOD 2461349525Smm if (fd >= 0) 2462349525Smm fchmod(fd, p->mode); 2463349525Smm else 2464349525Smm#endif 2465228753Smm chmod(p->name, p->mode); 2466349525Smm } 2467231200Smm if (p->fixup & TODO_ACLS) 2468349525Smm archive_write_disk_set_acls(&a->archive, fd, 2469349525Smm p->name, &p->acl, p->mode); 2470228753Smm if (p->fixup & TODO_FFLAGS) 2471349525Smm set_fflags_platform(a, fd, p->name, 2472228753Smm p->mode, p->fflags_set, 0); 2473231200Smm if (p->fixup & TODO_MAC_METADATA) 2474231200Smm set_mac_metadata(a, p->name, p->mac_metadata, 2475231200Smm p->mac_metadata_size); 2476228753Smm next = p->next; 2477231200Smm archive_acl_clear(&p->acl); 2478231200Smm free(p->mac_metadata); 2479228753Smm free(p->name); 2480349525Smm if (fd >= 0) 2481349525Smm close(fd); 2482228753Smm free(p); 2483228753Smm p = next; 2484228753Smm } 2485228753Smm a->fixup_list = NULL; 2486228753Smm return (ret); 2487228753Smm} 2488228753Smm 2489228753Smmstatic int 2490231200Smm_archive_write_disk_free(struct archive *_a) 2491228753Smm{ 2492231200Smm struct archive_write_disk *a; 2493228753Smm int ret; 2494231200Smm if (_a == NULL) 2495231200Smm return (ARCHIVE_OK); 2496231200Smm archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC, 2497231200Smm ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); 2498231200Smm a = (struct archive_write_disk *)_a; 2499231200Smm ret = _archive_write_disk_close(&a->archive); 2500231200Smm archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); 2501231200Smm archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); 2502344674Smm archive_entry_free(a->entry); 2503228753Smm archive_string_free(&a->_name_data); 2504358090Smm archive_string_free(&a->_tmpname_data); 2505228753Smm archive_string_free(&a->archive.error_string); 2506228753Smm archive_string_free(&a->path_safe); 2507231200Smm a->archive.magic = 0; 2508231200Smm __archive_clean(&a->archive); 2509248616Smm free(a->decmpfs_header_p); 2510248616Smm free(a->resource_fork); 2511248616Smm free(a->compressed_buffer); 2512248616Smm free(a->uncompressed_buffer); 2513302001Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ 2514302001Smm && defined(HAVE_ZLIB_H) 2515248616Smm if (a->stream_valid) { 2516248616Smm switch (deflateEnd(&a->stream)) { 2517248616Smm case Z_OK: 2518248616Smm break; 2519248616Smm default: 2520248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 2521248616Smm "Failed to clean up compressor"); 2522248616Smm ret = ARCHIVE_FATAL; 2523248616Smm break; 2524248616Smm } 2525248616Smm } 2526248616Smm#endif 2527228753Smm free(a); 2528228753Smm return (ret); 2529228753Smm} 2530228753Smm 2531228753Smm/* 2532228753Smm * Simple O(n log n) merge sort to order the fixup list. In 2533228753Smm * particular, we want to restore dir timestamps depth-first. 2534228753Smm */ 2535228753Smmstatic struct fixup_entry * 2536228753Smmsort_dir_list(struct fixup_entry *p) 2537228753Smm{ 2538228753Smm struct fixup_entry *a, *b, *t; 2539228753Smm 2540228753Smm if (p == NULL) 2541228753Smm return (NULL); 2542228753Smm /* A one-item list is already sorted. */ 2543228753Smm if (p->next == NULL) 2544228753Smm return (p); 2545228753Smm 2546228753Smm /* Step 1: split the list. */ 2547228753Smm t = p; 2548228753Smm a = p->next->next; 2549228753Smm while (a != NULL) { 2550228753Smm /* Step a twice, t once. */ 2551228753Smm a = a->next; 2552228753Smm if (a != NULL) 2553228753Smm a = a->next; 2554228753Smm t = t->next; 2555228753Smm } 2556228753Smm /* Now, t is at the mid-point, so break the list here. */ 2557228753Smm b = t->next; 2558228753Smm t->next = NULL; 2559228753Smm a = p; 2560228753Smm 2561228753Smm /* Step 2: Recursively sort the two sub-lists. */ 2562228753Smm a = sort_dir_list(a); 2563228753Smm b = sort_dir_list(b); 2564228753Smm 2565228753Smm /* Step 3: Merge the returned lists. */ 2566228753Smm /* Pick the first element for the merged list. */ 2567228753Smm if (strcmp(a->name, b->name) > 0) { 2568228753Smm t = p = a; 2569228753Smm a = a->next; 2570228753Smm } else { 2571228753Smm t = p = b; 2572228753Smm b = b->next; 2573228753Smm } 2574228753Smm 2575228753Smm /* Always put the later element on the list first. */ 2576228753Smm while (a != NULL && b != NULL) { 2577228753Smm if (strcmp(a->name, b->name) > 0) { 2578228753Smm t->next = a; 2579228753Smm a = a->next; 2580228753Smm } else { 2581228753Smm t->next = b; 2582228753Smm b = b->next; 2583228753Smm } 2584228753Smm t = t->next; 2585228753Smm } 2586228753Smm 2587228753Smm /* Only one list is non-empty, so just splice it on. */ 2588228753Smm if (a != NULL) 2589228753Smm t->next = a; 2590228753Smm if (b != NULL) 2591228753Smm t->next = b; 2592228753Smm 2593228753Smm return (p); 2594228753Smm} 2595228753Smm 2596228753Smm/* 2597228753Smm * Returns a new, initialized fixup entry. 2598228753Smm * 2599228753Smm * TODO: Reduce the memory requirements for this list by using a tree 2600228753Smm * structure rather than a simple list of names. 2601228753Smm */ 2602228753Smmstatic struct fixup_entry * 2603228753Smmnew_fixup(struct archive_write_disk *a, const char *pathname) 2604228753Smm{ 2605228753Smm struct fixup_entry *fe; 2606228753Smm 2607231200Smm fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry)); 2608248616Smm if (fe == NULL) { 2609248616Smm archive_set_error(&a->archive, ENOMEM, 2610248616Smm "Can't allocate memory for a fixup"); 2611228753Smm return (NULL); 2612248616Smm } 2613228753Smm fe->next = a->fixup_list; 2614228753Smm a->fixup_list = fe; 2615228753Smm fe->fixup = 0; 2616228753Smm fe->name = strdup(pathname); 2617228753Smm return (fe); 2618228753Smm} 2619228753Smm 2620228753Smm/* 2621228753Smm * Returns a fixup structure for the current entry. 2622228753Smm */ 2623228753Smmstatic struct fixup_entry * 2624228753Smmcurrent_fixup(struct archive_write_disk *a, const char *pathname) 2625228753Smm{ 2626228753Smm if (a->current_fixup == NULL) 2627228753Smm a->current_fixup = new_fixup(a, pathname); 2628228753Smm return (a->current_fixup); 2629228753Smm} 2630228753Smm 2631309702Smm/* Error helper for new *_fsobj functions */ 2632309702Smmstatic void 2633309702Smmfsobj_error(int *a_eno, struct archive_string *a_estr, 2634309702Smm int err, const char *errstr, const char *path) 2635309702Smm{ 2636309702Smm if (a_eno) 2637309702Smm *a_eno = err; 2638309702Smm if (a_estr) 2639315433Smm archive_string_sprintf(a_estr, "%s%s", errstr, path); 2640309702Smm} 2641309702Smm 2642228753Smm/* 2643228753Smm * TODO: Someday, integrate this with the deep dir support; they both 2644228753Smm * scan the path and both can be optimized by comparing against other 2645228753Smm * recent paths. 2646228753Smm */ 2647306322Smm/* 2648306322Smm * Checks the given path to see if any elements along it are symlinks. Returns 2649306322Smm * ARCHIVE_OK if there are none, otherwise puts an error in errmsg. 2650306322Smm */ 2651228753Smmstatic int 2652309702Smmcheck_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, 2653309702Smm int flags) 2654228753Smm{ 2655349525Smm#if !defined(HAVE_LSTAT) && \ 2656349525Smm !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)) 2657228753Smm /* Platform doesn't have lstat, so we can't look for symlinks. */ 2658306322Smm (void)path; /* UNUSED */ 2659306322Smm (void)error_number; /* UNUSED */ 2660306322Smm (void)error_string; /* UNUSED */ 2661306322Smm (void)flags; /* UNUSED */ 2662228753Smm return (ARCHIVE_OK); 2663228753Smm#else 2664306322Smm int res = ARCHIVE_OK; 2665306322Smm char *tail; 2666306322Smm char *head; 2667306322Smm int last; 2668228753Smm char c; 2669228753Smm int r; 2670228753Smm struct stat st; 2671349525Smm int chdir_fd; 2672349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) 2673349525Smm int fd; 2674349525Smm#endif 2675228753Smm 2676306322Smm /* Nothing to do here if name is empty */ 2677306322Smm if(path[0] == '\0') 2678306322Smm return (ARCHIVE_OK); 2679306322Smm 2680228753Smm /* 2681228753Smm * Guard against symlink tricks. Reject any archive entry whose 2682228753Smm * destination would be altered by a symlink. 2683306322Smm * 2684306322Smm * Walk the filename in chunks separated by '/'. For each segment: 2685306322Smm * - if it doesn't exist, continue 2686306322Smm * - if it's symlink, abort or remove it 2687306322Smm * - if it's a directory and it's not the last chunk, cd into it 2688306322Smm * As we go: 2689306322Smm * head points to the current (relative) path 2690309702Smm * tail points to the temporary \0 terminating the segment we're 2691309702Smm * currently examining 2692306322Smm * c holds what used to be in *tail 2693306322Smm * last is 1 if this is the last tail 2694228753Smm */ 2695349525Smm chdir_fd = la_opendirat(AT_FDCWD, "."); 2696349525Smm __archive_ensure_cloexec_flag(chdir_fd); 2697349525Smm if (chdir_fd < 0) { 2698346105Smm fsobj_error(a_eno, a_estr, errno, 2699346105Smm "Could not open ", path); 2700306322Smm return (ARCHIVE_FATAL); 2701346105Smm } 2702306322Smm head = path; 2703306322Smm tail = path; 2704306322Smm last = 0; 2705306322Smm /* TODO: reintroduce a safe cache here? */ 2706302001Smm /* Skip the root directory if the path is absolute. */ 2707306322Smm if(tail == path && tail[0] == '/') 2708306322Smm ++tail; 2709306322Smm /* Keep going until we've checked the entire name. 2710306322Smm * head, tail, path all alias the same string, which is 2711306322Smm * temporarily zeroed at tail, so be careful restoring the 2712306322Smm * stashed (c=tail[0]) for error messages. 2713306322Smm * Exiting the loop with break is okay; continue is not. 2714306322Smm */ 2715306322Smm while (!last) { 2716309702Smm /* 2717309702Smm * Skip the separator we just consumed, plus any adjacent ones 2718309702Smm */ 2719306322Smm while (*tail == '/') 2720306322Smm ++tail; 2721228753Smm /* Skip the next path element. */ 2722306322Smm while (*tail != '\0' && *tail != '/') 2723306322Smm ++tail; 2724306322Smm /* is this the last path component? */ 2725306322Smm last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0'); 2726306322Smm /* temporarily truncate the string here */ 2727306322Smm c = tail[0]; 2728306322Smm tail[0] = '\0'; 2729228753Smm /* Check that we haven't hit a symlink. */ 2730349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) 2731349525Smm r = fstatat(chdir_fd, head, &st, AT_SYMLINK_NOFOLLOW); 2732349525Smm#else 2733306322Smm r = lstat(head, &st); 2734349525Smm#endif 2735228753Smm if (r != 0) { 2736306322Smm tail[0] = c; 2737228753Smm /* We've hit a dir that doesn't exist; stop now. */ 2738305192Smm if (errno == ENOENT) { 2739228753Smm break; 2740305192Smm } else { 2741309702Smm /* 2742309702Smm * Treat any other error as fatal - best to be 2743309702Smm * paranoid here. 2744309702Smm * Note: This effectively disables deep 2745309702Smm * directory support when security checks are 2746309702Smm * enabled. Otherwise, very long pathnames that 2747309702Smm * trigger an error here could evade the 2748309702Smm * sandbox. 2749309702Smm * TODO: We could do better, but it would 2750309702Smm * probably require merging the symlink checks 2751309702Smm * with the deep-directory editing. 2752309702Smm */ 2753309702Smm fsobj_error(a_eno, a_estr, errno, 2754315433Smm "Could not stat ", path); 2755306322Smm res = ARCHIVE_FAILED; 2756306322Smm break; 2757305192Smm } 2758306322Smm } else if (S_ISDIR(st.st_mode)) { 2759306322Smm if (!last) { 2760349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) 2761349525Smm fd = la_opendirat(chdir_fd, head); 2762349525Smm if (fd < 0) 2763349525Smm r = -1; 2764349525Smm else { 2765349525Smm r = 0; 2766349525Smm close(chdir_fd); 2767349525Smm chdir_fd = fd; 2768349525Smm } 2769349525Smm#else 2770349525Smm r = chdir(head); 2771349525Smm#endif 2772349525Smm if (r != 0) { 2773306322Smm tail[0] = c; 2774309702Smm fsobj_error(a_eno, a_estr, errno, 2775315433Smm "Could not chdir ", path); 2776306322Smm res = (ARCHIVE_FATAL); 2777306322Smm break; 2778306322Smm } 2779306322Smm /* Our view is now from inside this dir: */ 2780306322Smm head = tail + 1; 2781306322Smm } 2782228753Smm } else if (S_ISLNK(st.st_mode)) { 2783306322Smm if (last) { 2784228753Smm /* 2785228753Smm * Last element is symlink; remove it 2786228753Smm * so we can overwrite it with the 2787228753Smm * item being extracted. 2788228753Smm */ 2789349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) 2790349525Smm r = unlinkat(chdir_fd, head, 0); 2791349525Smm#else 2792349525Smm r = unlink(head); 2793349525Smm#endif 2794349525Smm if (r != 0) { 2795306322Smm tail[0] = c; 2796309702Smm fsobj_error(a_eno, a_estr, errno, 2797315433Smm "Could not remove symlink ", 2798309702Smm path); 2799306322Smm res = ARCHIVE_FAILED; 2800306322Smm break; 2801228753Smm } 2802228753Smm /* 2803228753Smm * Even if we did remove it, a warning 2804228753Smm * is in order. The warning is silly, 2805228753Smm * though, if we're just replacing one 2806228753Smm * symlink with another symlink. 2807228753Smm */ 2808306322Smm tail[0] = c; 2809309702Smm /* 2810309702Smm * FIXME: not sure how important this is to 2811309702Smm * restore 2812309702Smm */ 2813309702Smm /* 2814306322Smm if (!S_ISLNK(path)) { 2815309702Smm fsobj_error(a_eno, a_estr, 0, 2816315433Smm "Removing symlink ", path); 2817228753Smm } 2818306322Smm */ 2819228753Smm /* Symlink gone. No more problem! */ 2820306322Smm res = ARCHIVE_OK; 2821306322Smm break; 2822306322Smm } else if (flags & ARCHIVE_EXTRACT_UNLINK) { 2823228753Smm /* User asked us to remove problems. */ 2824349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) 2825349525Smm r = unlinkat(chdir_fd, head, 0); 2826349525Smm#else 2827349525Smm r = unlink(head); 2828349525Smm#endif 2829349525Smm if (r != 0) { 2830306322Smm tail[0] = c; 2831309702Smm fsobj_error(a_eno, a_estr, 0, 2832309702Smm "Cannot remove intervening " 2833315433Smm "symlink ", path); 2834306322Smm res = ARCHIVE_FAILED; 2835306322Smm break; 2836228753Smm } 2837306322Smm tail[0] = c; 2838309702Smm } else if ((flags & 2839309702Smm ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) { 2840309702Smm /* 2841309702Smm * We are not the last element and we want to 2842309702Smm * follow symlinks if they are a directory. 2843309702Smm * 2844309702Smm * This is needed to extract hardlinks over 2845309702Smm * symlinks. 2846309702Smm */ 2847349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) 2848349525Smm r = fstatat(chdir_fd, head, &st, 0); 2849349525Smm#else 2850348608Smm r = la_stat(head, &st); 2851349525Smm#endif 2852309702Smm if (r != 0) { 2853309702Smm tail[0] = c; 2854309702Smm if (errno == ENOENT) { 2855309702Smm break; 2856309702Smm } else { 2857309702Smm fsobj_error(a_eno, a_estr, 2858309702Smm errno, 2859315433Smm "Could not stat ", path); 2860309702Smm res = (ARCHIVE_FAILED); 2861309702Smm break; 2862309702Smm } 2863309702Smm } else if (S_ISDIR(st.st_mode)) { 2864349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) 2865349525Smm fd = la_opendirat(chdir_fd, head); 2866349525Smm if (fd < 0) 2867349525Smm r = -1; 2868349525Smm else { 2869349525Smm r = 0; 2870349525Smm close(chdir_fd); 2871349525Smm chdir_fd = fd; 2872349525Smm } 2873349525Smm#else 2874349525Smm r = chdir(head); 2875349525Smm#endif 2876349525Smm if (r != 0) { 2877309702Smm tail[0] = c; 2878309702Smm fsobj_error(a_eno, a_estr, 2879309702Smm errno, 2880315433Smm "Could not chdir ", path); 2881309702Smm res = (ARCHIVE_FATAL); 2882309702Smm break; 2883309702Smm } 2884309702Smm /* 2885309702Smm * Our view is now from inside 2886309702Smm * this dir: 2887309702Smm */ 2888309702Smm head = tail + 1; 2889309702Smm } else { 2890309702Smm tail[0] = c; 2891309702Smm fsobj_error(a_eno, a_estr, 0, 2892309702Smm "Cannot extract through " 2893315433Smm "symlink ", path); 2894309702Smm res = ARCHIVE_FAILED; 2895309702Smm break; 2896309702Smm } 2897228753Smm } else { 2898306322Smm tail[0] = c; 2899309702Smm fsobj_error(a_eno, a_estr, 0, 2900315433Smm "Cannot extract through symlink ", path); 2901306322Smm res = ARCHIVE_FAILED; 2902306322Smm break; 2903228753Smm } 2904228753Smm } 2905306322Smm /* be sure to always maintain this */ 2906306322Smm tail[0] = c; 2907306322Smm if (tail[0] != '\0') 2908306322Smm tail++; /* Advance to the next segment. */ 2909228753Smm } 2910306322Smm /* Catches loop exits via break */ 2911306322Smm tail[0] = c; 2912349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) 2913349525Smm /* If we operate with openat(), fstatat() and unlinkat() there was 2914349525Smm * no chdir(), so just close the fd */ 2915349525Smm if (chdir_fd >= 0) 2916349525Smm close(chdir_fd); 2917349525Smm#elif HAVE_FCHDIR 2918306322Smm /* If we changed directory above, restore it here. */ 2919349525Smm if (chdir_fd >= 0) { 2920349525Smm r = fchdir(chdir_fd); 2921306322Smm if (r != 0) { 2922309702Smm fsobj_error(a_eno, a_estr, errno, 2923309702Smm "chdir() failure", ""); 2924306322Smm } 2925349525Smm close(chdir_fd); 2926349525Smm chdir_fd = -1; 2927306322Smm if (r != 0) { 2928306322Smm res = (ARCHIVE_FATAL); 2929306322Smm } 2930306322Smm } 2931228753Smm#endif 2932306322Smm /* TODO: reintroduce a safe cache here? */ 2933306322Smm return res; 2934306322Smm#endif 2935228753Smm} 2936228753Smm 2937306322Smm/* 2938306322Smm * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise 2939306322Smm * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED} 2940306322Smm */ 2941306322Smmstatic int 2942306322Smmcheck_symlinks(struct archive_write_disk *a) 2943306322Smm{ 2944306322Smm struct archive_string error_string; 2945306322Smm int error_number; 2946306322Smm int rc; 2947306322Smm archive_string_init(&error_string); 2948309702Smm rc = check_symlinks_fsobj(a->name, &error_number, &error_string, 2949309702Smm a->flags); 2950306322Smm if (rc != ARCHIVE_OK) { 2951309702Smm archive_set_error(&a->archive, error_number, "%s", 2952309702Smm error_string.s); 2953306322Smm } 2954306322Smm archive_string_free(&error_string); 2955306322Smm a->pst = NULL; /* to be safe */ 2956306322Smm return rc; 2957306322Smm} 2958306322Smm 2959306322Smm 2960231200Smm#if defined(__CYGWIN__) 2961228753Smm/* 2962228753Smm * 1. Convert a path separator from '\' to '/' . 2963231200Smm * We shouldn't check multibyte character directly because some 2964228753Smm * character-set have been using the '\' character for a part of 2965228753Smm * its multibyte character code. 2966228753Smm * 2. Replace unusable characters in Windows with underscore('_'). 2967228753Smm * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx 2968228753Smm */ 2969231200Smmstatic void 2970311042Smmcleanup_pathname_win(char *path) 2971228753Smm{ 2972228753Smm wchar_t wc; 2973228753Smm char *p; 2974228753Smm size_t alen, l; 2975231200Smm int mb, complete, utf8; 2976228753Smm 2977231200Smm alen = 0; 2978231200Smm mb = 0; 2979231200Smm complete = 1; 2980231200Smm utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0; 2981311042Smm for (p = path; *p != '\0'; p++) { 2982231200Smm ++alen; 2983231200Smm if (*p == '\\') { 2984231200Smm /* If previous byte is smaller than 128, 2985231200Smm * this is not second byte of multibyte characters, 2986231200Smm * so we can replace '\' with '/'. */ 2987231200Smm if (utf8 || !mb) 2988231200Smm *p = '/'; 2989228753Smm else 2990231200Smm complete = 0;/* uncompleted. */ 2991231200Smm } else if (*(unsigned char *)p > 127) 2992231200Smm mb = 1; 2993231200Smm else 2994231200Smm mb = 0; 2995231200Smm /* Rewrite the path name if its next character is unusable. */ 2996228753Smm if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || 2997228753Smm *p == '<' || *p == '>' || *p == '|') 2998228753Smm *p = '_'; 2999228753Smm } 3000231200Smm if (complete) 3001231200Smm return; 3002231200Smm 3003228753Smm /* 3004231200Smm * Convert path separator in wide-character. 3005228753Smm */ 3006311042Smm p = path; 3007228753Smm while (*p != '\0' && alen) { 3008228753Smm l = mbtowc(&wc, p, alen); 3009232153Smm if (l == (size_t)-1) { 3010228753Smm while (*p != '\0') { 3011228753Smm if (*p == '\\') 3012228753Smm *p = '/'; 3013228753Smm ++p; 3014228753Smm } 3015228753Smm break; 3016228753Smm } 3017228753Smm if (l == 1 && wc == L'\\') 3018228753Smm *p = '/'; 3019228753Smm p += l; 3020228753Smm alen -= l; 3021228753Smm } 3022228753Smm} 3023228753Smm#endif 3024228753Smm 3025228753Smm/* 3026228753Smm * Canonicalize the pathname. In particular, this strips duplicate 3027228753Smm * '/' characters, '.' elements, and trailing '/'. It also raises an 3028300361Smm * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is 3029300361Smm * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS 3030300361Smm * is set) if the path is absolute. 3031228753Smm */ 3032228753Smmstatic int 3033309702Smmcleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr, 3034309702Smm int flags) 3035228753Smm{ 3036228753Smm char *dest, *src; 3037228753Smm char separator = '\0'; 3038228753Smm 3039306322Smm dest = src = path; 3040228753Smm if (*src == '\0') { 3041309702Smm fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, 3042309702Smm "Invalid empty ", "pathname"); 3043228753Smm return (ARCHIVE_FAILED); 3044228753Smm } 3045228753Smm 3046231200Smm#if defined(__CYGWIN__) 3047311042Smm cleanup_pathname_win(path); 3048228753Smm#endif 3049228753Smm /* Skip leading '/'. */ 3050300361Smm if (*src == '/') { 3051306322Smm if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) { 3052309702Smm fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, 3053309702Smm "Path is ", "absolute"); 3054300361Smm return (ARCHIVE_FAILED); 3055300361Smm } 3056300361Smm 3057228753Smm separator = *src++; 3058300361Smm } 3059228753Smm 3060228753Smm /* Scan the pathname one element at a time. */ 3061228753Smm for (;;) { 3062228753Smm /* src points to first char after '/' */ 3063228753Smm if (src[0] == '\0') { 3064228753Smm break; 3065228753Smm } else if (src[0] == '/') { 3066228753Smm /* Found '//', ignore second one. */ 3067228753Smm src++; 3068228753Smm continue; 3069228753Smm } else if (src[0] == '.') { 3070228753Smm if (src[1] == '\0') { 3071228753Smm /* Ignore trailing '.' */ 3072228753Smm break; 3073228753Smm } else if (src[1] == '/') { 3074228753Smm /* Skip './'. */ 3075228753Smm src += 2; 3076228753Smm continue; 3077228753Smm } else if (src[1] == '.') { 3078228753Smm if (src[2] == '/' || src[2] == '\0') { 3079228753Smm /* Conditionally warn about '..' */ 3080309702Smm if (flags 3081309702Smm & ARCHIVE_EXTRACT_SECURE_NODOTDOT) { 3082309702Smm fsobj_error(a_eno, a_estr, 3083309702Smm ARCHIVE_ERRNO_MISC, 3084309702Smm "Path contains ", "'..'"); 3085228753Smm return (ARCHIVE_FAILED); 3086228753Smm } 3087228753Smm } 3088228753Smm /* 3089228753Smm * Note: Under no circumstances do we 3090228753Smm * remove '..' elements. In 3091228753Smm * particular, restoring 3092228753Smm * '/foo/../bar/' should create the 3093228753Smm * 'foo' dir as a side-effect. 3094228753Smm */ 3095228753Smm } 3096228753Smm } 3097228753Smm 3098228753Smm /* Copy current element, including leading '/'. */ 3099228753Smm if (separator) 3100228753Smm *dest++ = '/'; 3101228753Smm while (*src != '\0' && *src != '/') { 3102228753Smm *dest++ = *src++; 3103228753Smm } 3104228753Smm 3105228753Smm if (*src == '\0') 3106228753Smm break; 3107228753Smm 3108228753Smm /* Skip '/' separator. */ 3109228753Smm separator = *src++; 3110228753Smm } 3111228753Smm /* 3112228753Smm * We've just copied zero or more path elements, not including the 3113228753Smm * final '/'. 3114228753Smm */ 3115306322Smm if (dest == path) { 3116228753Smm /* 3117228753Smm * Nothing got copied. The path must have been something 3118228753Smm * like '.' or '/' or './' or '/././././/./'. 3119228753Smm */ 3120228753Smm if (separator) 3121228753Smm *dest++ = '/'; 3122228753Smm else 3123228753Smm *dest++ = '.'; 3124228753Smm } 3125228753Smm /* Terminate the result. */ 3126228753Smm *dest = '\0'; 3127228753Smm return (ARCHIVE_OK); 3128228753Smm} 3129228753Smm 3130306322Smmstatic int 3131306322Smmcleanup_pathname(struct archive_write_disk *a) 3132306322Smm{ 3133306322Smm struct archive_string error_string; 3134306322Smm int error_number; 3135306322Smm int rc; 3136306322Smm archive_string_init(&error_string); 3137309702Smm rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string, 3138309702Smm a->flags); 3139306322Smm if (rc != ARCHIVE_OK) { 3140309702Smm archive_set_error(&a->archive, error_number, "%s", 3141309702Smm error_string.s); 3142306322Smm } 3143306322Smm archive_string_free(&error_string); 3144306322Smm return rc; 3145306322Smm} 3146306322Smm 3147228753Smm/* 3148228753Smm * Create the parent directory of the specified path, assuming path 3149228753Smm * is already in mutable storage. 3150228753Smm */ 3151228753Smmstatic int 3152228753Smmcreate_parent_dir(struct archive_write_disk *a, char *path) 3153228753Smm{ 3154228753Smm char *slash; 3155228753Smm int r; 3156228753Smm 3157228753Smm /* Remove tail element to obtain parent name. */ 3158228753Smm slash = strrchr(path, '/'); 3159228753Smm if (slash == NULL) 3160228753Smm return (ARCHIVE_OK); 3161228753Smm *slash = '\0'; 3162228753Smm r = create_dir(a, path); 3163228753Smm *slash = '/'; 3164228753Smm return (r); 3165228753Smm} 3166228753Smm 3167228753Smm/* 3168228753Smm * Create the specified dir, recursing to create parents as necessary. 3169228753Smm * 3170228753Smm * Returns ARCHIVE_OK if the path exists when we're done here. 3171228753Smm * Otherwise, returns ARCHIVE_FAILED. 3172228753Smm * Assumes path is in mutable storage; path is unchanged on exit. 3173228753Smm */ 3174228753Smmstatic int 3175228753Smmcreate_dir(struct archive_write_disk *a, char *path) 3176228753Smm{ 3177228753Smm struct stat st; 3178228753Smm struct fixup_entry *le; 3179228753Smm char *slash, *base; 3180228753Smm mode_t mode_final, mode; 3181228753Smm int r; 3182228753Smm 3183228753Smm /* Check for special names and just skip them. */ 3184228753Smm slash = strrchr(path, '/'); 3185228753Smm if (slash == NULL) 3186228753Smm base = path; 3187228753Smm else 3188228753Smm base = slash + 1; 3189228753Smm 3190228753Smm if (base[0] == '\0' || 3191228753Smm (base[0] == '.' && base[1] == '\0') || 3192228753Smm (base[0] == '.' && base[1] == '.' && base[2] == '\0')) { 3193228753Smm /* Don't bother trying to create null path, '.', or '..'. */ 3194228753Smm if (slash != NULL) { 3195228753Smm *slash = '\0'; 3196228753Smm r = create_dir(a, path); 3197228753Smm *slash = '/'; 3198228753Smm return (r); 3199228753Smm } 3200228753Smm return (ARCHIVE_OK); 3201228753Smm } 3202228753Smm 3203228753Smm /* 3204228753Smm * Yes, this should be stat() and not lstat(). Using lstat() 3205228753Smm * here loses the ability to extract through symlinks. Also note 3206228753Smm * that this should not use the a->st cache. 3207228753Smm */ 3208348608Smm if (la_stat(path, &st) == 0) { 3209228753Smm if (S_ISDIR(st.st_mode)) 3210228753Smm return (ARCHIVE_OK); 3211228753Smm if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { 3212228753Smm archive_set_error(&a->archive, EEXIST, 3213228753Smm "Can't create directory '%s'", path); 3214228753Smm return (ARCHIVE_FAILED); 3215228753Smm } 3216228753Smm if (unlink(path) != 0) { 3217228753Smm archive_set_error(&a->archive, errno, 3218228753Smm "Can't create directory '%s': " 3219231200Smm "Conflicting file cannot be removed", 3220231200Smm path); 3221228753Smm return (ARCHIVE_FAILED); 3222228753Smm } 3223228753Smm } else if (errno != ENOENT && errno != ENOTDIR) { 3224228753Smm /* Stat failed? */ 3225309702Smm archive_set_error(&a->archive, errno, 3226309702Smm "Can't test directory '%s'", path); 3227228753Smm return (ARCHIVE_FAILED); 3228228753Smm } else if (slash != NULL) { 3229228753Smm *slash = '\0'; 3230228753Smm r = create_dir(a, path); 3231228753Smm *slash = '/'; 3232228753Smm if (r != ARCHIVE_OK) 3233228753Smm return (r); 3234228753Smm } 3235228753Smm 3236228753Smm /* 3237228753Smm * Mode we want for the final restored directory. Per POSIX, 3238228753Smm * implicitly-created dirs must be created obeying the umask. 3239228753Smm * There's no mention whether this is different for privileged 3240228753Smm * restores (which the rest of this code handles by pretending 3241228753Smm * umask=0). I've chosen here to always obey the user's umask for 3242228753Smm * implicit dirs, even if _EXTRACT_PERM was specified. 3243228753Smm */ 3244228753Smm mode_final = DEFAULT_DIR_MODE & ~a->user_umask; 3245228753Smm /* Mode we want on disk during the restore process. */ 3246228753Smm mode = mode_final; 3247228753Smm mode |= MINIMUM_DIR_MODE; 3248228753Smm mode &= MAXIMUM_DIR_MODE; 3249228753Smm if (mkdir(path, mode) == 0) { 3250228753Smm if (mode != mode_final) { 3251228753Smm le = new_fixup(a, path); 3252248616Smm if (le == NULL) 3253248616Smm return (ARCHIVE_FATAL); 3254228753Smm le->fixup |=TODO_MODE_BASE; 3255228753Smm le->mode = mode_final; 3256228753Smm } 3257228753Smm return (ARCHIVE_OK); 3258228753Smm } 3259228753Smm 3260228753Smm /* 3261228753Smm * Without the following check, a/b/../b/c/d fails at the 3262228753Smm * second visit to 'b', so 'd' can't be created. Note that we 3263228753Smm * don't add it to the fixup list here, as it's already been 3264228753Smm * added. 3265228753Smm */ 3266348608Smm if (la_stat(path, &st) == 0 && S_ISDIR(st.st_mode)) 3267228753Smm return (ARCHIVE_OK); 3268228753Smm 3269228753Smm archive_set_error(&a->archive, errno, "Failed to create dir '%s'", 3270228753Smm path); 3271228753Smm return (ARCHIVE_FAILED); 3272228753Smm} 3273228753Smm 3274228753Smm/* 3275228753Smm * Note: Although we can skip setting the user id if the desired user 3276228753Smm * id matches the current user, we cannot skip setting the group, as 3277228753Smm * many systems set the gid based on the containing directory. So 3278228753Smm * we have to perform a chown syscall if we want to set the SGID 3279228753Smm * bit. (The alternative is to stat() and then possibly chown(); it's 3280228753Smm * more efficient to skip the stat() and just always chown().) Note 3281228753Smm * that a successful chown() here clears the TODO_SGID_CHECK bit, which 3282228753Smm * allows set_mode to skip the stat() check for the GID. 3283228753Smm */ 3284228753Smmstatic int 3285228753Smmset_ownership(struct archive_write_disk *a) 3286228753Smm{ 3287346105Smm#if !defined(__CYGWIN__) && !defined(__linux__) 3288346105Smm/* 3289346105Smm * On Linux, a process may have the CAP_CHOWN capability. 3290346105Smm * On Windows there is no 'root' user with uid 0. 3291346105Smm * Elsewhere we can skip calling chown if we are not root and the desired 3292346105Smm * user id does not match the current user. 3293346105Smm */ 3294346105Smm if (a->user_uid != 0 && a->user_uid != a->uid) { 3295228753Smm archive_set_error(&a->archive, errno, 3296231200Smm "Can't set UID=%jd", (intmax_t)a->uid); 3297228753Smm return (ARCHIVE_WARN); 3298228753Smm } 3299228753Smm#endif 3300228753Smm 3301228753Smm#ifdef HAVE_FCHOWN 3302228753Smm /* If we have an fd, we can avoid a race. */ 3303228753Smm if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) { 3304228753Smm /* We've set owner and know uid/gid are correct. */ 3305228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 3306228753Smm return (ARCHIVE_OK); 3307228753Smm } 3308228753Smm#endif 3309228753Smm 3310228753Smm /* We prefer lchown() but will use chown() if that's all we have. */ 3311228753Smm /* Of course, if we have neither, this will always fail. */ 3312228753Smm#ifdef HAVE_LCHOWN 3313228753Smm if (lchown(a->name, a->uid, a->gid) == 0) { 3314228753Smm /* We've set owner and know uid/gid are correct. */ 3315228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 3316228753Smm return (ARCHIVE_OK); 3317228753Smm } 3318228753Smm#elif HAVE_CHOWN 3319228753Smm if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) { 3320228753Smm /* We've set owner and know uid/gid are correct. */ 3321228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 3322228753Smm return (ARCHIVE_OK); 3323228753Smm } 3324228753Smm#endif 3325228753Smm 3326228753Smm archive_set_error(&a->archive, errno, 3327231200Smm "Can't set user=%jd/group=%jd for %s", 3328231200Smm (intmax_t)a->uid, (intmax_t)a->gid, a->name); 3329228753Smm return (ARCHIVE_WARN); 3330228753Smm} 3331228753Smm 3332231200Smm/* 3333231200Smm * Note: Returns 0 on success, non-zero on failure. 3334228753Smm */ 3335228753Smmstatic int 3336228753Smmset_time(int fd, int mode, const char *name, 3337228753Smm time_t atime, long atime_nsec, 3338228753Smm time_t mtime, long mtime_nsec) 3339228753Smm{ 3340231200Smm /* Select the best implementation for this platform. */ 3341231200Smm#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS) 3342231200Smm /* 3343231200Smm * utimensat() and futimens() are defined in 3344231200Smm * POSIX.1-2008. They support ns resolution and setting times 3345231200Smm * on fds and symlinks. 3346231200Smm */ 3347228753Smm struct timespec ts[2]; 3348232153Smm (void)mode; /* UNUSED */ 3349228753Smm ts[0].tv_sec = atime; 3350228753Smm ts[0].tv_nsec = atime_nsec; 3351228753Smm ts[1].tv_sec = mtime; 3352228753Smm ts[1].tv_nsec = mtime_nsec; 3353228753Smm if (fd >= 0) 3354228753Smm return futimens(fd, ts); 3355228753Smm return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW); 3356231200Smm 3357228753Smm#elif HAVE_UTIMES 3358231200Smm /* 3359231200Smm * The utimes()-family functions support ��s-resolution and 3360231200Smm * setting times fds and symlinks. utimes() is documented as 3361231200Smm * LEGACY by POSIX, futimes() and lutimes() are not described 3362231200Smm * in POSIX. 3363231200Smm */ 3364228753Smm struct timeval times[2]; 3365228753Smm 3366228753Smm times[0].tv_sec = atime; 3367228753Smm times[0].tv_usec = atime_nsec / 1000; 3368228753Smm times[1].tv_sec = mtime; 3369228753Smm times[1].tv_usec = mtime_nsec / 1000; 3370228753Smm 3371228753Smm#ifdef HAVE_FUTIMES 3372228753Smm if (fd >= 0) 3373228753Smm return (futimes(fd, times)); 3374228753Smm#else 3375228753Smm (void)fd; /* UNUSED */ 3376228753Smm#endif 3377228753Smm#ifdef HAVE_LUTIMES 3378228753Smm (void)mode; /* UNUSED */ 3379228753Smm return (lutimes(name, times)); 3380228753Smm#else 3381228753Smm if (S_ISLNK(mode)) 3382228753Smm return (0); 3383228753Smm return (utimes(name, times)); 3384228753Smm#endif 3385231200Smm 3386228753Smm#elif defined(HAVE_UTIME) 3387231200Smm /* 3388231200Smm * utime() is POSIX-standard but only supports 1s resolution and 3389231200Smm * does not support fds or symlinks. 3390231200Smm */ 3391228753Smm struct utimbuf times; 3392228753Smm (void)fd; /* UNUSED */ 3393228753Smm (void)name; /* UNUSED */ 3394228753Smm (void)atime_nsec; /* UNUSED */ 3395228753Smm (void)mtime_nsec; /* UNUSED */ 3396228753Smm times.actime = atime; 3397228753Smm times.modtime = mtime; 3398228753Smm if (S_ISLNK(mode)) 3399228753Smm return (ARCHIVE_OK); 3400228753Smm return (utime(name, ×)); 3401231200Smm 3402231200Smm#else 3403231200Smm /* 3404231200Smm * We don't know how to set the time on this platform. 3405231200Smm */ 3406232153Smm (void)fd; /* UNUSED */ 3407232153Smm (void)mode; /* UNUSED */ 3408232153Smm (void)name; /* UNUSED */ 3409232153Smm (void)atime_nsec; /* UNUSED */ 3410232153Smm (void)mtime_nsec; /* UNUSED */ 3411231200Smm return (ARCHIVE_WARN); 3412231200Smm#endif 3413228753Smm} 3414231200Smm 3415302001Smm#ifdef F_SETTIMES 3416228753Smmstatic int 3417231200Smmset_time_tru64(int fd, int mode, const char *name, 3418228753Smm time_t atime, long atime_nsec, 3419231200Smm time_t mtime, long mtime_nsec, 3420231200Smm time_t ctime, long ctime_nsec) 3421228753Smm{ 3422231200Smm struct attr_timbuf tstamp; 3423302001Smm tstamp.atime.tv_sec = atime; 3424302001Smm tstamp.mtime.tv_sec = mtime; 3425302001Smm tstamp.ctime.tv_sec = ctime; 3426302001Smm#if defined (__hpux) && defined (__ia64) 3427302001Smm tstamp.atime.tv_nsec = atime_nsec; 3428302001Smm tstamp.mtime.tv_nsec = mtime_nsec; 3429302001Smm tstamp.ctime.tv_nsec = ctime_nsec; 3430302001Smm#else 3431302001Smm tstamp.atime.tv_usec = atime_nsec / 1000; 3432302001Smm tstamp.mtime.tv_usec = mtime_nsec / 1000; 3433302001Smm tstamp.ctime.tv_usec = ctime_nsec / 1000; 3434302001Smm#endif 3435231200Smm return (fcntl(fd,F_SETTIMES,&tstamp)); 3436228753Smm} 3437302001Smm#endif /* F_SETTIMES */ 3438231200Smm 3439231200Smmstatic int 3440231200Smmset_times(struct archive_write_disk *a, 3441231200Smm int fd, int mode, const char *name, 3442231200Smm time_t atime, long atime_nanos, 3443231200Smm time_t birthtime, long birthtime_nanos, 3444231200Smm time_t mtime, long mtime_nanos, 3445232153Smm time_t cctime, long ctime_nanos) 3446231200Smm{ 3447231200Smm /* Note: set_time doesn't use libarchive return conventions! 3448231200Smm * It uses syscall conventions. So 0 here instead of ARCHIVE_OK. */ 3449231200Smm int r1 = 0, r2 = 0; 3450231200Smm 3451231200Smm#ifdef F_SETTIMES 3452231200Smm /* 3453231200Smm * on Tru64 try own fcntl first which can restore even the 3454231200Smm * ctime, fall back to default code path below if it fails 3455231200Smm * or if we are not running as root 3456231200Smm */ 3457231200Smm if (a->user_uid == 0 && 3458231200Smm set_time_tru64(fd, mode, name, 3459231200Smm atime, atime_nanos, mtime, 3460232153Smm mtime_nanos, cctime, ctime_nanos) == 0) { 3461231200Smm return (ARCHIVE_OK); 3462231200Smm } 3463232153Smm#else /* Tru64 */ 3464232153Smm (void)cctime; /* UNUSED */ 3465232153Smm (void)ctime_nanos; /* UNUSED */ 3466231200Smm#endif /* Tru64 */ 3467231200Smm 3468231200Smm#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME 3469231200Smm /* 3470231200Smm * If you have struct stat.st_birthtime, we assume BSD 3471231200Smm * birthtime semantics, in which {f,l,}utimes() updates 3472231200Smm * birthtime to earliest mtime. So we set the time twice, 3473231200Smm * first using the birthtime, then using the mtime. If 3474231200Smm * birthtime == mtime, this isn't necessary, so we skip it. 3475231200Smm * If birthtime > mtime, then this won't work, so we skip it. 3476231200Smm */ 3477231200Smm if (birthtime < mtime 3478231200Smm || (birthtime == mtime && birthtime_nanos < mtime_nanos)) 3479231200Smm r1 = set_time(fd, mode, name, 3480231200Smm atime, atime_nanos, 3481231200Smm birthtime, birthtime_nanos); 3482232153Smm#else 3483232153Smm (void)birthtime; /* UNUSED */ 3484232153Smm (void)birthtime_nanos; /* UNUSED */ 3485228753Smm#endif 3486231200Smm r2 = set_time(fd, mode, name, 3487231200Smm atime, atime_nanos, 3488231200Smm mtime, mtime_nanos); 3489231200Smm if (r1 != 0 || r2 != 0) { 3490231200Smm archive_set_error(&a->archive, errno, 3491231200Smm "Can't restore time"); 3492231200Smm return (ARCHIVE_WARN); 3493231200Smm } 3494231200Smm return (ARCHIVE_OK); 3495231200Smm} 3496228753Smm 3497228753Smmstatic int 3498231200Smmset_times_from_entry(struct archive_write_disk *a) 3499228753Smm{ 3500232153Smm time_t atime, birthtime, mtime, cctime; 3501231200Smm long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec; 3502228753Smm 3503231200Smm /* Suitable defaults. */ 3504232153Smm atime = birthtime = mtime = cctime = a->start_time; 3505231200Smm atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0; 3506231200Smm 3507228753Smm /* If no time was provided, we're done. */ 3508228753Smm if (!archive_entry_atime_is_set(a->entry) 3509228753Smm#if HAVE_STRUCT_STAT_ST_BIRTHTIME 3510228753Smm && !archive_entry_birthtime_is_set(a->entry) 3511228753Smm#endif 3512228753Smm && !archive_entry_mtime_is_set(a->entry)) 3513228753Smm return (ARCHIVE_OK); 3514228753Smm 3515228753Smm if (archive_entry_atime_is_set(a->entry)) { 3516228753Smm atime = archive_entry_atime(a->entry); 3517228753Smm atime_nsec = archive_entry_atime_nsec(a->entry); 3518228753Smm } 3519231200Smm if (archive_entry_birthtime_is_set(a->entry)) { 3520231200Smm birthtime = archive_entry_birthtime(a->entry); 3521231200Smm birthtime_nsec = archive_entry_birthtime_nsec(a->entry); 3522231200Smm } 3523228753Smm if (archive_entry_mtime_is_set(a->entry)) { 3524228753Smm mtime = archive_entry_mtime(a->entry); 3525228753Smm mtime_nsec = archive_entry_mtime_nsec(a->entry); 3526228753Smm } 3527231200Smm if (archive_entry_ctime_is_set(a->entry)) { 3528232153Smm cctime = archive_entry_ctime(a->entry); 3529231200Smm ctime_nsec = archive_entry_ctime_nsec(a->entry); 3530228753Smm } 3531228753Smm 3532231200Smm return set_times(a, a->fd, a->mode, a->name, 3533231200Smm atime, atime_nsec, 3534231200Smm birthtime, birthtime_nsec, 3535231200Smm mtime, mtime_nsec, 3536232153Smm cctime, ctime_nsec); 3537228753Smm} 3538228753Smm 3539228753Smmstatic int 3540228753Smmset_mode(struct archive_write_disk *a, int mode) 3541228753Smm{ 3542228753Smm int r = ARCHIVE_OK; 3543349525Smm int r2; 3544228753Smm mode &= 07777; /* Strip off file type bits. */ 3545228753Smm 3546228753Smm if (a->todo & TODO_SGID_CHECK) { 3547228753Smm /* 3548228753Smm * If we don't know the GID is right, we must stat() 3549228753Smm * to verify it. We can't just check the GID of this 3550228753Smm * process, since systems sometimes set GID from 3551228753Smm * the enclosing dir or based on ACLs. 3552228753Smm */ 3553231200Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 3554228753Smm return (r); 3555228753Smm if (a->pst->st_gid != a->gid) { 3556228753Smm mode &= ~ S_ISGID; 3557228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 3558228753Smm /* 3559228753Smm * This is only an error if you 3560228753Smm * requested owner restore. If you 3561228753Smm * didn't, we'll try to restore 3562228753Smm * sgid/suid, but won't consider it a 3563228753Smm * problem if we can't. 3564228753Smm */ 3565228753Smm archive_set_error(&a->archive, -1, 3566228753Smm "Can't restore SGID bit"); 3567228753Smm r = ARCHIVE_WARN; 3568228753Smm } 3569228753Smm } 3570228753Smm /* While we're here, double-check the UID. */ 3571228753Smm if (a->pst->st_uid != a->uid 3572228753Smm && (a->todo & TODO_SUID)) { 3573228753Smm mode &= ~ S_ISUID; 3574228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 3575228753Smm archive_set_error(&a->archive, -1, 3576228753Smm "Can't restore SUID bit"); 3577228753Smm r = ARCHIVE_WARN; 3578228753Smm } 3579228753Smm } 3580228753Smm a->todo &= ~TODO_SGID_CHECK; 3581228753Smm a->todo &= ~TODO_SUID_CHECK; 3582228753Smm } else if (a->todo & TODO_SUID_CHECK) { 3583228753Smm /* 3584228753Smm * If we don't know the UID is right, we can just check 3585228753Smm * the user, since all systems set the file UID from 3586228753Smm * the process UID. 3587228753Smm */ 3588228753Smm if (a->user_uid != a->uid) { 3589228753Smm mode &= ~ S_ISUID; 3590228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 3591228753Smm archive_set_error(&a->archive, -1, 3592228753Smm "Can't make file SUID"); 3593228753Smm r = ARCHIVE_WARN; 3594228753Smm } 3595228753Smm } 3596228753Smm a->todo &= ~TODO_SUID_CHECK; 3597228753Smm } 3598228753Smm 3599228753Smm if (S_ISLNK(a->mode)) { 3600228753Smm#ifdef HAVE_LCHMOD 3601228753Smm /* 3602228753Smm * If this is a symlink, use lchmod(). If the 3603228753Smm * platform doesn't support lchmod(), just skip it. A 3604228753Smm * platform that doesn't provide a way to set 3605228753Smm * permissions on symlinks probably ignores 3606228753Smm * permissions on symlinks, so a failure here has no 3607228753Smm * impact. 3608228753Smm */ 3609228753Smm if (lchmod(a->name, mode) != 0) { 3610302001Smm switch (errno) { 3611302001Smm case ENOTSUP: 3612302001Smm case ENOSYS: 3613302001Smm#if ENOTSUP != EOPNOTSUPP 3614302001Smm case EOPNOTSUPP: 3615302001Smm#endif 3616302001Smm /* 3617302001Smm * if lchmod is defined but the platform 3618302001Smm * doesn't support it, silently ignore 3619302001Smm * error 3620302001Smm */ 3621302001Smm break; 3622302001Smm default: 3623302001Smm archive_set_error(&a->archive, errno, 3624302001Smm "Can't set permissions to 0%o", (int)mode); 3625302001Smm r = ARCHIVE_WARN; 3626302001Smm } 3627228753Smm } 3628228753Smm#endif 3629228753Smm } else if (!S_ISDIR(a->mode)) { 3630228753Smm /* 3631228753Smm * If it's not a symlink and not a dir, then use 3632228753Smm * fchmod() or chmod(), depending on whether we have 3633228753Smm * an fd. Dirs get their perms set during the 3634228753Smm * post-extract fixup, which is handled elsewhere. 3635228753Smm */ 3636228753Smm#ifdef HAVE_FCHMOD 3637349525Smm if (a->fd >= 0) 3638349525Smm r2 = fchmod(a->fd, mode); 3639349525Smm else 3640228753Smm#endif 3641349525Smm /* If this platform lacks fchmod(), then 3642349525Smm * we'll just use chmod(). */ 3643349525Smm r2 = chmod(a->name, mode); 3644349525Smm 3645349525Smm if (r2 != 0) { 3646349525Smm archive_set_error(&a->archive, errno, 3647349525Smm "Can't set permissions to 0%o", (int)mode); 3648349525Smm r = ARCHIVE_WARN; 3649349525Smm } 3650228753Smm } 3651228753Smm return (r); 3652228753Smm} 3653228753Smm 3654228753Smmstatic int 3655228753Smmset_fflags(struct archive_write_disk *a) 3656228753Smm{ 3657228753Smm struct fixup_entry *le; 3658228753Smm unsigned long set, clear; 3659228753Smm int r; 3660228753Smm mode_t mode = archive_entry_mode(a->entry); 3661228753Smm /* 3662228753Smm * Make 'critical_flags' hold all file flags that can't be 3663228753Smm * immediately restored. For example, on BSD systems, 3664228753Smm * SF_IMMUTABLE prevents hardlinks from being created, so 3665228753Smm * should not be set until after any hardlinks are created. To 3666228753Smm * preserve some semblance of portability, this uses #ifdef 3667228753Smm * extensively. Ugly, but it works. 3668228753Smm * 3669228753Smm * Yes, Virginia, this does create a security race. It's mitigated 3670228753Smm * somewhat by the practice of creating dirs 0700 until the extract 3671228753Smm * is done, but it would be nice if we could do more than that. 3672228753Smm * People restoring critical file systems should be wary of 3673228753Smm * other programs that might try to muck with files as they're 3674228753Smm * being restored. 3675228753Smm */ 3676346105Smm const int critical_flags = 0 3677228753Smm#ifdef SF_IMMUTABLE 3678346105Smm | SF_IMMUTABLE 3679228753Smm#endif 3680228753Smm#ifdef UF_IMMUTABLE 3681346105Smm | UF_IMMUTABLE 3682228753Smm#endif 3683228753Smm#ifdef SF_APPEND 3684346105Smm | SF_APPEND 3685228753Smm#endif 3686228753Smm#ifdef UF_APPEND 3687346105Smm | UF_APPEND 3688228753Smm#endif 3689315433Smm#if defined(FS_APPEND_FL) 3690346105Smm | FS_APPEND_FL 3691315433Smm#elif defined(EXT2_APPEND_FL) 3692346105Smm | EXT2_APPEND_FL 3693228753Smm#endif 3694315433Smm#if defined(FS_IMMUTABLE_FL) 3695346105Smm | FS_IMMUTABLE_FL 3696315433Smm#elif defined(EXT2_IMMUTABLE_FL) 3697346105Smm | EXT2_IMMUTABLE_FL 3698228753Smm#endif 3699315433Smm#ifdef FS_JOURNAL_DATA_FL 3700346105Smm | FS_JOURNAL_DATA_FL 3701315433Smm#endif 3702346105Smm ; 3703228753Smm 3704228753Smm if (a->todo & TODO_FFLAGS) { 3705228753Smm archive_entry_fflags(a->entry, &set, &clear); 3706228753Smm 3707228753Smm /* 3708228753Smm * The first test encourages the compiler to eliminate 3709228753Smm * all of this if it's not necessary. 3710228753Smm */ 3711228753Smm if ((critical_flags != 0) && (set & critical_flags)) { 3712228753Smm le = current_fixup(a, a->name); 3713248616Smm if (le == NULL) 3714248616Smm return (ARCHIVE_FATAL); 3715228753Smm le->fixup |= TODO_FFLAGS; 3716228753Smm le->fflags_set = set; 3717228753Smm /* Store the mode if it's not already there. */ 3718228753Smm if ((le->fixup & TODO_MODE) == 0) 3719228753Smm le->mode = mode; 3720228753Smm } else { 3721228753Smm r = set_fflags_platform(a, a->fd, 3722228753Smm a->name, mode, set, clear); 3723228753Smm if (r != ARCHIVE_OK) 3724228753Smm return (r); 3725228753Smm } 3726228753Smm } 3727228753Smm return (ARCHIVE_OK); 3728228753Smm} 3729228753Smm 3730302001Smmstatic int 3731302001Smmclear_nochange_fflags(struct archive_write_disk *a) 3732302001Smm{ 3733302001Smm mode_t mode = archive_entry_mode(a->entry); 3734346105Smm const int nochange_flags = 0 3735302001Smm#ifdef SF_IMMUTABLE 3736346105Smm | SF_IMMUTABLE 3737302001Smm#endif 3738302001Smm#ifdef UF_IMMUTABLE 3739346105Smm | UF_IMMUTABLE 3740302001Smm#endif 3741302001Smm#ifdef SF_APPEND 3742346105Smm | SF_APPEND 3743302001Smm#endif 3744302001Smm#ifdef UF_APPEND 3745346105Smm | UF_APPEND 3746302001Smm#endif 3747302001Smm#ifdef EXT2_APPEND_FL 3748346105Smm | EXT2_APPEND_FL 3749302001Smm#endif 3750302001Smm#ifdef EXT2_IMMUTABLE_FL 3751346105Smm | EXT2_IMMUTABLE_FL 3752302001Smm#endif 3753346105Smm ; 3754302001Smm 3755309702Smm return (set_fflags_platform(a, a->fd, a->name, mode, 0, 3756309702Smm nochange_flags)); 3757302001Smm} 3758302001Smm 3759302001Smm 3760228753Smm#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS) 3761228753Smm/* 3762228753Smm * BSD reads flags using stat() and sets them with one of {f,l,}chflags() 3763228753Smm */ 3764228753Smmstatic int 3765228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 3766228753Smm mode_t mode, unsigned long set, unsigned long clear) 3767228753Smm{ 3768228753Smm int r; 3769346105Smm const int sf_mask = 0 3770346105Smm#ifdef SF_APPEND 3771346105Smm | SF_APPEND 3772346105Smm#endif 3773346105Smm#ifdef SF_ARCHIVED 3774346105Smm | SF_ARCHIVED 3775346105Smm#endif 3776346105Smm#ifdef SF_IMMUTABLE 3777346105Smm | SF_IMMUTABLE 3778346105Smm#endif 3779346105Smm#ifdef SF_NOUNLINK 3780346105Smm | SF_NOUNLINK 3781346105Smm#endif 3782346105Smm ; 3783346105Smm (void)mode; /* UNUSED */ 3784228753Smm 3785228753Smm if (set == 0 && clear == 0) 3786228753Smm return (ARCHIVE_OK); 3787228753Smm 3788228753Smm /* 3789228753Smm * XXX Is the stat here really necessary? Or can I just use 3790228753Smm * the 'set' flags directly? In particular, I'm not sure 3791228753Smm * about the correct approach if we're overwriting an existing 3792228753Smm * file that already has flags on it. XXX 3793228753Smm */ 3794231200Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 3795228753Smm return (r); 3796228753Smm 3797228753Smm a->st.st_flags &= ~clear; 3798228753Smm a->st.st_flags |= set; 3799346105Smm 3800346105Smm /* Only super-user may change SF_* flags */ 3801346105Smm 3802346105Smm if (a->user_uid != 0) 3803346105Smm a->st.st_flags &= ~sf_mask; 3804346105Smm 3805228753Smm#ifdef HAVE_FCHFLAGS 3806228753Smm /* If platform has fchflags() and we were given an fd, use it. */ 3807228753Smm if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0) 3808228753Smm return (ARCHIVE_OK); 3809228753Smm#endif 3810228753Smm /* 3811228753Smm * If we can't use the fd to set the flags, we'll use the 3812228753Smm * pathname to set flags. We prefer lchflags() but will use 3813228753Smm * chflags() if we must. 3814228753Smm */ 3815228753Smm#ifdef HAVE_LCHFLAGS 3816228753Smm if (lchflags(name, a->st.st_flags) == 0) 3817228753Smm return (ARCHIVE_OK); 3818228753Smm#elif defined(HAVE_CHFLAGS) 3819228753Smm if (S_ISLNK(a->st.st_mode)) { 3820228753Smm archive_set_error(&a->archive, errno, 3821228753Smm "Can't set file flags on symlink."); 3822228753Smm return (ARCHIVE_WARN); 3823228753Smm } 3824228753Smm if (chflags(name, a->st.st_flags) == 0) 3825228753Smm return (ARCHIVE_OK); 3826228753Smm#endif 3827228753Smm archive_set_error(&a->archive, errno, 3828228753Smm "Failed to set file flags"); 3829228753Smm return (ARCHIVE_WARN); 3830228753Smm} 3831228753Smm 3832315433Smm#elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \ 3833315433Smm defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ 3834315433Smm (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \ 3835315433Smm defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) 3836228753Smm/* 3837228753Smm * Linux uses ioctl() to read and write file flags. 3838228753Smm */ 3839228753Smmstatic int 3840228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 3841228753Smm mode_t mode, unsigned long set, unsigned long clear) 3842228753Smm{ 3843228753Smm int ret; 3844228753Smm int myfd = fd; 3845248616Smm int newflags, oldflags; 3846346105Smm /* 3847346105Smm * Linux has no define for the flags that are only settable by 3848346105Smm * the root user. This code may seem a little complex, but 3849346105Smm * there seem to be some Linux systems that lack these 3850346105Smm * defines. (?) The code below degrades reasonably gracefully 3851346105Smm * if sf_mask is incomplete. 3852346105Smm */ 3853346105Smm const int sf_mask = 0 3854346105Smm#if defined(FS_IMMUTABLE_FL) 3855346105Smm | FS_IMMUTABLE_FL 3856346105Smm#elif defined(EXT2_IMMUTABLE_FL) 3857346105Smm | EXT2_IMMUTABLE_FL 3858346105Smm#endif 3859346105Smm#if defined(FS_APPEND_FL) 3860346105Smm | FS_APPEND_FL 3861346105Smm#elif defined(EXT2_APPEND_FL) 3862346105Smm | EXT2_APPEND_FL 3863346105Smm#endif 3864346105Smm#if defined(FS_JOURNAL_DATA_FL) 3865346105Smm | FS_JOURNAL_DATA_FL 3866346105Smm#endif 3867346105Smm ; 3868228753Smm 3869315433Smm if (set == 0 && clear == 0) 3870228753Smm return (ARCHIVE_OK); 3871228753Smm /* Only regular files and dirs can have flags. */ 3872228753Smm if (!S_ISREG(mode) && !S_ISDIR(mode)) 3873228753Smm return (ARCHIVE_OK); 3874228753Smm 3875228753Smm /* If we weren't given an fd, open it ourselves. */ 3876248616Smm if (myfd < 0) { 3877248616Smm myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC); 3878248616Smm __archive_ensure_cloexec_flag(myfd); 3879248616Smm } 3880228753Smm if (myfd < 0) 3881228753Smm return (ARCHIVE_OK); 3882228753Smm 3883228753Smm /* 3884228753Smm * XXX As above, this would be way simpler if we didn't have 3885228753Smm * to read the current flags from disk. XXX 3886228753Smm */ 3887228753Smm ret = ARCHIVE_OK; 3888231200Smm 3889231200Smm /* Read the current file flags. */ 3890315433Smm if (ioctl(myfd, 3891315433Smm#ifdef FS_IOC_GETFLAGS 3892315433Smm FS_IOC_GETFLAGS, 3893315433Smm#else 3894315433Smm EXT2_IOC_GETFLAGS, 3895315433Smm#endif 3896315433Smm &oldflags) < 0) 3897231200Smm goto fail; 3898231200Smm 3899228753Smm /* Try setting the flags as given. */ 3900231200Smm newflags = (oldflags & ~clear) | set; 3901315433Smm if (ioctl(myfd, 3902315433Smm#ifdef FS_IOC_SETFLAGS 3903315433Smm FS_IOC_SETFLAGS, 3904315433Smm#else 3905315433Smm EXT2_IOC_SETFLAGS, 3906315433Smm#endif 3907315433Smm &newflags) >= 0) 3908231200Smm goto cleanup; 3909231200Smm if (errno != EPERM) 3910231200Smm goto fail; 3911231200Smm 3912228753Smm /* If we couldn't set all the flags, try again with a subset. */ 3913231200Smm newflags &= ~sf_mask; 3914231200Smm oldflags &= sf_mask; 3915231200Smm newflags |= oldflags; 3916315433Smm if (ioctl(myfd, 3917315433Smm#ifdef FS_IOC_SETFLAGS 3918315433Smm FS_IOC_SETFLAGS, 3919315433Smm#else 3920315433Smm EXT2_IOC_SETFLAGS, 3921315433Smm#endif 3922315433Smm &newflags) >= 0) 3923231200Smm goto cleanup; 3924231200Smm 3925228753Smm /* We couldn't set the flags, so report the failure. */ 3926228753Smmfail: 3927228753Smm archive_set_error(&a->archive, errno, 3928228753Smm "Failed to set file flags"); 3929228753Smm ret = ARCHIVE_WARN; 3930228753Smmcleanup: 3931228753Smm if (fd < 0) 3932228753Smm close(myfd); 3933228753Smm return (ret); 3934228753Smm} 3935228753Smm 3936228753Smm#else 3937228753Smm 3938228753Smm/* 3939228753Smm * Of course, some systems have neither BSD chflags() nor Linux' flags 3940228753Smm * support through ioctl(). 3941228753Smm */ 3942228753Smmstatic int 3943228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 3944228753Smm mode_t mode, unsigned long set, unsigned long clear) 3945228753Smm{ 3946228753Smm (void)a; /* UNUSED */ 3947228753Smm (void)fd; /* UNUSED */ 3948228753Smm (void)name; /* UNUSED */ 3949228753Smm (void)mode; /* UNUSED */ 3950228753Smm (void)set; /* UNUSED */ 3951228753Smm (void)clear; /* UNUSED */ 3952228753Smm return (ARCHIVE_OK); 3953228753Smm} 3954228753Smm 3955228753Smm#endif /* __linux */ 3956228753Smm 3957231200Smm#ifndef HAVE_COPYFILE_H 3958231200Smm/* Default is to simply drop Mac extended metadata. */ 3959231200Smmstatic int 3960231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname, 3961231200Smm const void *metadata, size_t metadata_size) 3962231200Smm{ 3963231200Smm (void)a; /* UNUSED */ 3964231200Smm (void)pathname; /* UNUSED */ 3965231200Smm (void)metadata; /* UNUSED */ 3966231200Smm (void)metadata_size; /* UNUSED */ 3967231200Smm return (ARCHIVE_OK); 3968231200Smm} 3969248616Smm 3970248616Smmstatic int 3971248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname) 3972248616Smm{ 3973248616Smm (void)a; /* UNUSED */ 3974248616Smm (void)pathname; /* UNUSED */ 3975248616Smm return (ARCHIVE_OK); 3976248616Smm} 3977231200Smm#else 3978231200Smm 3979231200Smm/* 3980231200Smm * On Mac OS, we use copyfile() to unpack the metadata and 3981231200Smm * apply it to the target file. 3982231200Smm */ 3983248616Smm 3984248616Smm#if defined(HAVE_SYS_XATTR_H) 3985231200Smmstatic int 3986248616Smmcopy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd) 3987248616Smm{ 3988248616Smm ssize_t xattr_size; 3989248616Smm char *xattr_names = NULL, *xattr_val = NULL; 3990248616Smm int ret = ARCHIVE_OK, xattr_i; 3991248616Smm 3992248616Smm xattr_size = flistxattr(tmpfd, NULL, 0, 0); 3993248616Smm if (xattr_size == -1) { 3994248616Smm archive_set_error(&a->archive, errno, 3995248616Smm "Failed to read metadata(xattr)"); 3996248616Smm ret = ARCHIVE_WARN; 3997248616Smm goto exit_xattr; 3998248616Smm } 3999248616Smm xattr_names = malloc(xattr_size); 4000248616Smm if (xattr_names == NULL) { 4001248616Smm archive_set_error(&a->archive, ENOMEM, 4002248616Smm "Can't allocate memory for metadata(xattr)"); 4003248616Smm ret = ARCHIVE_FATAL; 4004248616Smm goto exit_xattr; 4005248616Smm } 4006248616Smm xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0); 4007248616Smm if (xattr_size == -1) { 4008248616Smm archive_set_error(&a->archive, errno, 4009248616Smm "Failed to read metadata(xattr)"); 4010248616Smm ret = ARCHIVE_WARN; 4011248616Smm goto exit_xattr; 4012248616Smm } 4013248616Smm for (xattr_i = 0; xattr_i < xattr_size; 4014248616Smm xattr_i += strlen(xattr_names + xattr_i) + 1) { 4015302001Smm char *xattr_val_saved; 4016248616Smm ssize_t s; 4017248616Smm int f; 4018248616Smm 4019248616Smm s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0); 4020248616Smm if (s == -1) { 4021248616Smm archive_set_error(&a->archive, errno, 4022248616Smm "Failed to get metadata(xattr)"); 4023248616Smm ret = ARCHIVE_WARN; 4024248616Smm goto exit_xattr; 4025248616Smm } 4026302001Smm xattr_val_saved = xattr_val; 4027248616Smm xattr_val = realloc(xattr_val, s); 4028248616Smm if (xattr_val == NULL) { 4029248616Smm archive_set_error(&a->archive, ENOMEM, 4030248616Smm "Failed to get metadata(xattr)"); 4031248616Smm ret = ARCHIVE_WARN; 4032302001Smm free(xattr_val_saved); 4033248616Smm goto exit_xattr; 4034248616Smm } 4035248616Smm s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0); 4036248616Smm if (s == -1) { 4037248616Smm archive_set_error(&a->archive, errno, 4038248616Smm "Failed to get metadata(xattr)"); 4039248616Smm ret = ARCHIVE_WARN; 4040248616Smm goto exit_xattr; 4041248616Smm } 4042248616Smm f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0); 4043248616Smm if (f == -1) { 4044248616Smm archive_set_error(&a->archive, errno, 4045248616Smm "Failed to get metadata(xattr)"); 4046248616Smm ret = ARCHIVE_WARN; 4047248616Smm goto exit_xattr; 4048248616Smm } 4049248616Smm } 4050248616Smmexit_xattr: 4051248616Smm free(xattr_names); 4052248616Smm free(xattr_val); 4053248616Smm return (ret); 4054248616Smm} 4055248616Smm#endif 4056248616Smm 4057248616Smmstatic int 4058248616Smmcopy_acls(struct archive_write_disk *a, int tmpfd, int dffd) 4059248616Smm{ 4060302425Smm#ifndef HAVE_SYS_ACL_H 4061302425Smm return 0; 4062302425Smm#else 4063248616Smm acl_t acl, dfacl = NULL; 4064248616Smm int acl_r, ret = ARCHIVE_OK; 4065248616Smm 4066248616Smm acl = acl_get_fd(tmpfd); 4067248616Smm if (acl == NULL) { 4068248616Smm if (errno == ENOENT) 4069248616Smm /* There are not any ACLs. */ 4070248616Smm return (ret); 4071248616Smm archive_set_error(&a->archive, errno, 4072248616Smm "Failed to get metadata(acl)"); 4073248616Smm ret = ARCHIVE_WARN; 4074248616Smm goto exit_acl; 4075248616Smm } 4076248616Smm dfacl = acl_dup(acl); 4077248616Smm acl_r = acl_set_fd(dffd, dfacl); 4078248616Smm if (acl_r == -1) { 4079248616Smm archive_set_error(&a->archive, errno, 4080248616Smm "Failed to get metadata(acl)"); 4081248616Smm ret = ARCHIVE_WARN; 4082248616Smm goto exit_acl; 4083248616Smm } 4084248616Smmexit_acl: 4085248616Smm if (acl) 4086248616Smm acl_free(acl); 4087248616Smm if (dfacl) 4088248616Smm acl_free(dfacl); 4089248616Smm return (ret); 4090302425Smm#endif 4091248616Smm} 4092248616Smm 4093248616Smmstatic int 4094248616Smmcreate_tempdatafork(struct archive_write_disk *a, const char *pathname) 4095248616Smm{ 4096248616Smm struct archive_string tmpdatafork; 4097248616Smm int tmpfd; 4098248616Smm 4099248616Smm archive_string_init(&tmpdatafork); 4100248616Smm archive_strcpy(&tmpdatafork, "tar.md.XXXXXX"); 4101248616Smm tmpfd = mkstemp(tmpdatafork.s); 4102248616Smm if (tmpfd < 0) { 4103248616Smm archive_set_error(&a->archive, errno, 4104248616Smm "Failed to mkstemp"); 4105248616Smm archive_string_free(&tmpdatafork); 4106248616Smm return (-1); 4107248616Smm } 4108248616Smm if (copyfile(pathname, tmpdatafork.s, 0, 4109248616Smm COPYFILE_UNPACK | COPYFILE_NOFOLLOW 4110248616Smm | COPYFILE_ACL | COPYFILE_XATTR) < 0) { 4111248616Smm archive_set_error(&a->archive, errno, 4112248616Smm "Failed to restore metadata"); 4113248616Smm close(tmpfd); 4114248616Smm tmpfd = -1; 4115248616Smm } 4116248616Smm unlink(tmpdatafork.s); 4117248616Smm archive_string_free(&tmpdatafork); 4118248616Smm return (tmpfd); 4119248616Smm} 4120248616Smm 4121248616Smmstatic int 4122248616Smmcopy_metadata(struct archive_write_disk *a, const char *metadata, 4123248616Smm const char *datafork, int datafork_compressed) 4124248616Smm{ 4125248616Smm int ret = ARCHIVE_OK; 4126248616Smm 4127248616Smm if (datafork_compressed) { 4128248616Smm int dffd, tmpfd; 4129248616Smm 4130248616Smm tmpfd = create_tempdatafork(a, metadata); 4131248616Smm if (tmpfd == -1) 4132248616Smm return (ARCHIVE_WARN); 4133248616Smm 4134248616Smm /* 4135248616Smm * Do not open the data fork compressed by HFS+ compression 4136248616Smm * with at least a writing mode(O_RDWR or O_WRONLY). it 4137248616Smm * makes the data fork uncompressed. 4138248616Smm */ 4139248616Smm dffd = open(datafork, 0); 4140248616Smm if (dffd == -1) { 4141248616Smm archive_set_error(&a->archive, errno, 4142248616Smm "Failed to open the data fork for metadata"); 4143248616Smm close(tmpfd); 4144248616Smm return (ARCHIVE_WARN); 4145248616Smm } 4146248616Smm 4147248616Smm#if defined(HAVE_SYS_XATTR_H) 4148248616Smm ret = copy_xattrs(a, tmpfd, dffd); 4149248616Smm if (ret == ARCHIVE_OK) 4150248616Smm#endif 4151248616Smm ret = copy_acls(a, tmpfd, dffd); 4152248616Smm close(tmpfd); 4153248616Smm close(dffd); 4154248616Smm } else { 4155248616Smm if (copyfile(metadata, datafork, 0, 4156248616Smm COPYFILE_UNPACK | COPYFILE_NOFOLLOW 4157248616Smm | COPYFILE_ACL | COPYFILE_XATTR) < 0) { 4158248616Smm archive_set_error(&a->archive, errno, 4159248616Smm "Failed to restore metadata"); 4160248616Smm ret = ARCHIVE_WARN; 4161248616Smm } 4162248616Smm } 4163248616Smm return (ret); 4164248616Smm} 4165248616Smm 4166248616Smmstatic int 4167231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname, 4168231200Smm const void *metadata, size_t metadata_size) 4169231200Smm{ 4170231200Smm struct archive_string tmp; 4171231200Smm ssize_t written; 4172231200Smm int fd; 4173231200Smm int ret = ARCHIVE_OK; 4174231200Smm 4175231200Smm /* This would be simpler if copyfile() could just accept the 4176231200Smm * metadata as a block of memory; then we could sidestep this 4177231200Smm * silly dance of writing the data to disk just so that 4178231200Smm * copyfile() can read it back in again. */ 4179231200Smm archive_string_init(&tmp); 4180231200Smm archive_strcpy(&tmp, pathname); 4181231200Smm archive_strcat(&tmp, ".XXXXXX"); 4182231200Smm fd = mkstemp(tmp.s); 4183231200Smm 4184231200Smm if (fd < 0) { 4185231200Smm archive_set_error(&a->archive, errno, 4186231200Smm "Failed to restore metadata"); 4187248616Smm archive_string_free(&tmp); 4188231200Smm return (ARCHIVE_WARN); 4189231200Smm } 4190231200Smm written = write(fd, metadata, metadata_size); 4191231200Smm close(fd); 4192248616Smm if ((size_t)written != metadata_size) { 4193231200Smm archive_set_error(&a->archive, errno, 4194231200Smm "Failed to restore metadata"); 4195231200Smm ret = ARCHIVE_WARN; 4196248616Smm } else { 4197248616Smm int compressed; 4198248616Smm 4199248616Smm#if defined(UF_COMPRESSED) 4200248616Smm if ((a->todo & TODO_HFS_COMPRESSION) != 0 && 4201248616Smm (ret = lazy_stat(a)) == ARCHIVE_OK) 4202248616Smm compressed = a->st.st_flags & UF_COMPRESSED; 4203248616Smm else 4204248616Smm#endif 4205248616Smm compressed = 0; 4206248616Smm ret = copy_metadata(a, tmp.s, pathname, compressed); 4207231200Smm } 4208231200Smm unlink(tmp.s); 4209248616Smm archive_string_free(&tmp); 4210231200Smm return (ret); 4211231200Smm} 4212248616Smm 4213248616Smmstatic int 4214248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname) 4215248616Smm{ 4216248616Smm char buff[8]; 4217248616Smm struct stat st; 4218248616Smm const char *p; 4219248616Smm struct archive_string datafork; 4220248616Smm int fd = -1, ret = ARCHIVE_OK; 4221248616Smm 4222248616Smm archive_string_init(&datafork); 4223248616Smm /* Check if the current file name is a type of the resource 4224248616Smm * fork file. */ 4225248616Smm p = strrchr(pathname, '/'); 4226248616Smm if (p == NULL) 4227248616Smm p = pathname; 4228248616Smm else 4229248616Smm p++; 4230248616Smm if (p[0] != '.' || p[1] != '_') 4231248616Smm goto skip_appledouble; 4232248616Smm 4233248616Smm /* 4234248616Smm * Check if the data fork file exists. 4235248616Smm * 4236248616Smm * TODO: Check if this write disk object has handled it. 4237248616Smm */ 4238248616Smm archive_strncpy(&datafork, pathname, p - pathname); 4239248616Smm archive_strcat(&datafork, p + 2); 4240248616Smm if (lstat(datafork.s, &st) == -1 || 4241248616Smm (st.st_mode & AE_IFMT) != AE_IFREG) 4242248616Smm goto skip_appledouble; 4243248616Smm 4244248616Smm /* 4245248616Smm * Check if the file is in the AppleDouble form. 4246248616Smm */ 4247248616Smm fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC); 4248248616Smm __archive_ensure_cloexec_flag(fd); 4249248616Smm if (fd == -1) { 4250248616Smm archive_set_error(&a->archive, errno, 4251248616Smm "Failed to open a restoring file"); 4252248616Smm ret = ARCHIVE_WARN; 4253248616Smm goto skip_appledouble; 4254248616Smm } 4255248616Smm if (read(fd, buff, 8) == -1) { 4256248616Smm archive_set_error(&a->archive, errno, 4257248616Smm "Failed to read a restoring file"); 4258248616Smm close(fd); 4259248616Smm ret = ARCHIVE_WARN; 4260248616Smm goto skip_appledouble; 4261248616Smm } 4262248616Smm close(fd); 4263248616Smm /* Check AppleDouble Magic Code. */ 4264248616Smm if (archive_be32dec(buff) != 0x00051607) 4265248616Smm goto skip_appledouble; 4266248616Smm /* Check AppleDouble Version. */ 4267248616Smm if (archive_be32dec(buff+4) != 0x00020000) 4268248616Smm goto skip_appledouble; 4269248616Smm 4270248616Smm ret = copy_metadata(a, pathname, datafork.s, 4271248616Smm#if defined(UF_COMPRESSED) 4272248616Smm st.st_flags & UF_COMPRESSED); 4273248616Smm#else 4274248616Smm 0); 4275231200Smm#endif 4276248616Smm if (ret == ARCHIVE_OK) { 4277248616Smm unlink(pathname); 4278248616Smm ret = ARCHIVE_EOF; 4279248616Smm } 4280248616Smmskip_appledouble: 4281248616Smm archive_string_free(&datafork); 4282248616Smm return (ret); 4283248616Smm} 4284248616Smm#endif 4285231200Smm 4286316338Smm#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX 4287228753Smm/* 4288316338Smm * Restore extended attributes - Linux, Darwin and AIX implementations: 4289231200Smm * AIX' ea interface is syntaxwise identical to the Linux xattr interface. 4290228753Smm */ 4291228753Smmstatic int 4292228753Smmset_xattrs(struct archive_write_disk *a) 4293228753Smm{ 4294228753Smm struct archive_entry *entry = a->entry; 4295353377Smm struct archive_string errlist; 4296228753Smm int ret = ARCHIVE_OK; 4297228753Smm int i = archive_entry_xattr_reset(entry); 4298353377Smm short fail = 0; 4299228753Smm 4300353377Smm archive_string_init(&errlist); 4301353377Smm 4302228753Smm while (i--) { 4303228753Smm const char *name; 4304228753Smm const void *value; 4305228753Smm size_t size; 4306353377Smm int e; 4307353377Smm 4308228753Smm archive_entry_xattr_next(entry, &name, &value, &size); 4309353377Smm 4310353377Smm if (name == NULL) 4311353377Smm continue; 4312316338Smm#if ARCHIVE_XATTR_LINUX 4313353377Smm /* Linux: quietly skip POSIX.1e ACL extended attributes */ 4314353377Smm if (strncmp(name, "system.", 7) == 0 && 4315353377Smm (strcmp(name + 7, "posix_acl_access") == 0 || 4316353377Smm strcmp(name + 7, "posix_acl_default") == 0)) 4317353377Smm continue; 4318353377Smm if (strncmp(name, "trusted.SGI_", 12) == 0 && 4319353377Smm (strcmp(name + 12, "ACL_DEFAULT") == 0 || 4320353377Smm strcmp(name + 12, "ACL_FILE") == 0)) 4321353377Smm continue; 4322353377Smm 4323353377Smm /* Linux: xfsroot namespace is obsolete and unsupported */ 4324353377Smm if (strncmp(name, "xfsroot.", 8) == 0) { 4325353377Smm fail = 1; 4326353377Smm archive_strcat(&errlist, name); 4327353377Smm archive_strappend_char(&errlist, ' '); 4328353377Smm continue; 4329353377Smm } 4330353377Smm#endif 4331353377Smm 4332353377Smm if (a->fd >= 0) { 4333353377Smm#if ARCHIVE_XATTR_LINUX 4334353377Smm e = fsetxattr(a->fd, name, value, size, 0); 4335316338Smm#elif ARCHIVE_XATTR_DARWIN 4336353377Smm e = fsetxattr(a->fd, name, value, size, 0, 0); 4337316338Smm#elif ARCHIVE_XATTR_AIX 4338353377Smm e = fsetea(a->fd, name, value, size, 0); 4339228753Smm#endif 4340353377Smm } else { 4341316338Smm#if ARCHIVE_XATTR_LINUX 4342353377Smm e = lsetxattr(archive_entry_pathname(entry), 4343353377Smm name, value, size, 0); 4344316338Smm#elif ARCHIVE_XATTR_DARWIN 4345353377Smm e = setxattr(archive_entry_pathname(entry), 4346353377Smm name, value, size, 0, XATTR_NOFOLLOW); 4347316338Smm#elif ARCHIVE_XATTR_AIX 4348353377Smm e = lsetea(archive_entry_pathname(entry), 4349353377Smm name, value, size, 0); 4350231200Smm#endif 4351353377Smm } 4352353377Smm if (e == -1) { 4353228753Smm ret = ARCHIVE_WARN; 4354353377Smm archive_strcat(&errlist, name); 4355353377Smm archive_strappend_char(&errlist, ' '); 4356353377Smm if (errno != ENOTSUP && errno != ENOSYS) 4357353377Smm fail = 1; 4358228753Smm } 4359228753Smm } 4360353377Smm 4361353377Smm if (ret == ARCHIVE_WARN) { 4362353377Smm if (fail && errlist.length > 0) { 4363353377Smm errlist.length--; 4364353377Smm errlist.s[errlist.length] = '\0'; 4365353377Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 4366353377Smm "Cannot restore extended attributes: %s", 4367353377Smm errlist.s); 4368353377Smm } else 4369353377Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 4370353377Smm "Cannot restore extended " 4371353377Smm "attributes on this file system."); 4372353377Smm } 4373353377Smm 4374353377Smm archive_string_free(&errlist); 4375228753Smm return (ret); 4376228753Smm} 4377316338Smm#elif ARCHIVE_XATTR_FREEBSD 4378228753Smm/* 4379228753Smm * Restore extended attributes - FreeBSD implementation 4380228753Smm */ 4381228753Smmstatic int 4382228753Smmset_xattrs(struct archive_write_disk *a) 4383228753Smm{ 4384228753Smm struct archive_entry *entry = a->entry; 4385353377Smm struct archive_string errlist; 4386228753Smm int ret = ARCHIVE_OK; 4387228753Smm int i = archive_entry_xattr_reset(entry); 4388353377Smm short fail = 0; 4389228753Smm 4390353377Smm archive_string_init(&errlist); 4391353377Smm 4392228753Smm while (i--) { 4393228753Smm const char *name; 4394228753Smm const void *value; 4395228753Smm size_t size; 4396228753Smm archive_entry_xattr_next(entry, &name, &value, &size); 4397228753Smm if (name != NULL) { 4398248995Smdf ssize_t e; 4399228753Smm int namespace; 4400228753Smm 4401368708Smm namespace = EXTATTR_NAMESPACE_USER; 4402368708Smm 4403228753Smm if (strncmp(name, "user.", 5) == 0) { 4404228753Smm /* "user." attributes go to user namespace */ 4405228753Smm name += 5; 4406228753Smm namespace = EXTATTR_NAMESPACE_USER; 4407368708Smm } else if (strncmp(name, "system.", 7) == 0) { 4408368708Smm name += 7; 4409368708Smm namespace = EXTATTR_NAMESPACE_SYSTEM; 4410368708Smm if (!strcmp(name, "nfs4.acl") || 4411368708Smm !strcmp(name, "posix1e.acl_access") || 4412368708Smm !strcmp(name, "posix1e.acl_default")) 4413368708Smm continue; 4414228753Smm } else { 4415353377Smm /* Other namespaces are unsupported */ 4416353377Smm archive_strcat(&errlist, name); 4417353377Smm archive_strappend_char(&errlist, ' '); 4418353377Smm fail = 1; 4419228753Smm ret = ARCHIVE_WARN; 4420228753Smm continue; 4421228753Smm } 4422316338Smm 4423316338Smm if (a->fd >= 0) { 4424368708Smm /* 4425368708Smm * On FreeBSD, extattr_set_fd does not 4426368708Smm * return the same as 4427368708Smm * extattr_set_file. It returns zero 4428368708Smm * on success, non-zero on failure. 4429368708Smm * 4430368708Smm * We can detect the failure by 4431368708Smm * manually setting errno prior to the 4432368708Smm * call and checking after. 4433368708Smm * 4434368708Smm * If errno remains zero, fake the 4435368708Smm * return value by setting e to size. 4436368708Smm * 4437368708Smm * This is a hack for now until I 4438368708Smm * (Shawn Webb) get FreeBSD to fix the 4439368708Smm * issue, if that's even possible. 4440368708Smm */ 4441368708Smm errno = 0; 4442309702Smm e = extattr_set_fd(a->fd, namespace, name, 4443309702Smm value, size); 4444368708Smm if (e == 0 && errno == 0) { 4445368708Smm e = size; 4446368708Smm } 4447316338Smm } else { 4448316338Smm e = extattr_set_link( 4449309702Smm archive_entry_pathname(entry), namespace, 4450309702Smm name, value, size); 4451228753Smm } 4452248995Smdf if (e != (ssize_t)size) { 4453353377Smm archive_strcat(&errlist, name); 4454353377Smm archive_strappend_char(&errlist, ' '); 4455228753Smm ret = ARCHIVE_WARN; 4456353377Smm if (errno != ENOTSUP && errno != ENOSYS) 4457353377Smm fail = 1; 4458228753Smm } 4459228753Smm } 4460228753Smm } 4461353377Smm 4462353377Smm if (ret == ARCHIVE_WARN) { 4463353377Smm if (fail && errlist.length > 0) { 4464353377Smm errlist.length--; 4465353377Smm errlist.s[errlist.length] = '\0'; 4466353377Smm 4467353377Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 4468353377Smm "Cannot restore extended attributes: %s", 4469353377Smm errlist.s); 4470353377Smm } else 4471353377Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 4472353377Smm "Cannot restore extended " 4473353377Smm "attributes on this file system."); 4474353377Smm } 4475353377Smm 4476353377Smm archive_string_free(&errlist); 4477228753Smm return (ret); 4478228753Smm} 4479228753Smm#else 4480228753Smm/* 4481228753Smm * Restore extended attributes - stub implementation for unsupported systems 4482228753Smm */ 4483228753Smmstatic int 4484228753Smmset_xattrs(struct archive_write_disk *a) 4485228753Smm{ 4486228753Smm static int warning_done = 0; 4487228753Smm 4488228753Smm /* If there aren't any extended attributes, then it's okay not 4489228753Smm * to extract them, otherwise, issue a single warning. */ 4490228753Smm if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) { 4491228753Smm warning_done = 1; 4492228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 4493228753Smm "Cannot restore extended attributes on this system"); 4494228753Smm return (ARCHIVE_WARN); 4495228753Smm } 4496228753Smm /* Warning was already emitted; suppress further warnings. */ 4497228753Smm return (ARCHIVE_OK); 4498228753Smm} 4499228753Smm#endif 4500228753Smm 4501228753Smm/* 4502228753Smm * Test if file on disk is older than entry. 4503228753Smm */ 4504228753Smmstatic int 4505228753Smmolder(struct stat *st, struct archive_entry *entry) 4506228753Smm{ 4507228753Smm /* First, test the seconds and return if we have a definite answer. */ 4508228753Smm /* Definitely older. */ 4509313571Smm if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry))) 4510228753Smm return (1); 4511228753Smm /* Definitely younger. */ 4512313571Smm if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry))) 4513228753Smm return (0); 4514228753Smm /* If this platform supports fractional seconds, try those. */ 4515228753Smm#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 4516228753Smm /* Definitely older. */ 4517228753Smm if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry)) 4518228753Smm return (1); 4519228753Smm#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 4520228753Smm /* Definitely older. */ 4521228753Smm if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry)) 4522228753Smm return (1); 4523228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_N 4524228753Smm /* older. */ 4525228753Smm if (st->st_mtime_n < archive_entry_mtime_nsec(entry)) 4526228753Smm return (1); 4527228753Smm#elif HAVE_STRUCT_STAT_ST_UMTIME 4528228753Smm /* older. */ 4529228753Smm if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry)) 4530228753Smm return (1); 4531228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_USEC 4532228753Smm /* older. */ 4533228753Smm if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry)) 4534228753Smm return (1); 4535228753Smm#else 4536228753Smm /* This system doesn't have high-res timestamps. */ 4537228753Smm#endif 4538228753Smm /* Same age or newer, so not older. */ 4539228753Smm return (0); 4540228753Smm} 4541231200Smm 4542316338Smm#ifndef ARCHIVE_ACL_SUPPORT 4543316338Smmint 4544316338Smmarchive_write_disk_set_acls(struct archive *a, int fd, const char *name, 4545316338Smm struct archive_acl *abstract_acl, __LA_MODE_T mode) 4546316338Smm{ 4547316338Smm (void)a; /* UNUSED */ 4548316338Smm (void)fd; /* UNUSED */ 4549316338Smm (void)name; /* UNUSED */ 4550316338Smm (void)abstract_acl; /* UNUSED */ 4551316338Smm (void)mode; /* UNUSED */ 4552316338Smm return (ARCHIVE_OK); 4553316338Smm} 4554316338Smm#endif 4555316338Smm 4556231200Smm#endif /* !_WIN32 || __CYGWIN__ */ 4557231200Smm 4558