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 42248616Smm#if defined(HAVE_SYS_XATTR_H) 43228753Smm#include <sys/xattr.h> 44248616Smm#elif defined(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 113231200Smm#if __APPLE__ 114231200Smm#include <TargetConditionals.h> 115231200Smm#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H 116231200Smm#include <quarantine.h> 117231200Smm#define HAVE_QUARANTINE 1 118231200Smm#endif 119231200Smm#endif 120231200Smm 121248616Smm#ifdef HAVE_ZLIB_H 122248616Smm#include <zlib.h> 123248616Smm#endif 124248616Smm 125231200Smm/* TODO: Support Mac OS 'quarantine' feature. This is really just a 126231200Smm * standard tag to mark files that have been downloaded as "tainted". 127231200Smm * On Mac OS, we should mark the extracted files as tainted if the 128231200Smm * archive being read was tainted. Windows has a similar feature; we 129231200Smm * should investigate ways to support this generically. */ 130231200Smm 131228753Smm#include "archive.h" 132231200Smm#include "archive_acl_private.h" 133228753Smm#include "archive_string.h" 134248616Smm#include "archive_endian.h" 135228753Smm#include "archive_entry.h" 136228753Smm#include "archive_private.h" 137238909Smm#include "archive_write_disk_private.h" 138228753Smm 139228753Smm#ifndef O_BINARY 140228753Smm#define O_BINARY 0 141228753Smm#endif 142248616Smm#ifndef O_CLOEXEC 143306941Sdelphij#define O_CLOEXEC 0 144248616Smm#endif 145228753Smm 146306941Sdelphij/* Ignore non-int O_NOFOLLOW constant. */ 147306941Sdelphij/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */ 148306941Sdelphij#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX) 149306941Sdelphij#undef O_NOFOLLOW 150306941Sdelphij#endif 151306941Sdelphij 152306941Sdelphij#ifndef O_NOFOLLOW 153306941Sdelphij#define O_NOFOLLOW 0 154306941Sdelphij#endif 155306941Sdelphij 156228753Smmstruct fixup_entry { 157228753Smm struct fixup_entry *next; 158231200Smm struct archive_acl acl; 159228753Smm mode_t mode; 160228753Smm int64_t atime; 161228753Smm int64_t birthtime; 162228753Smm int64_t mtime; 163231200Smm int64_t ctime; 164228753Smm unsigned long atime_nanos; 165228753Smm unsigned long birthtime_nanos; 166228753Smm unsigned long mtime_nanos; 167231200Smm unsigned long ctime_nanos; 168228753Smm unsigned long fflags_set; 169231200Smm size_t mac_metadata_size; 170231200Smm void *mac_metadata; 171228753Smm int fixup; /* bitmask of what needs fixing */ 172228753Smm char *name; 173228753Smm}; 174228753Smm 175228753Smm/* 176228753Smm * We use a bitmask to track which operations remain to be done for 177228753Smm * this file. In particular, this helps us avoid unnecessary 178228753Smm * operations when it's possible to take care of one step as a 179228753Smm * side-effect of another. For example, mkdir() can specify the mode 180228753Smm * for the newly-created object but symlink() cannot. This means we 181228753Smm * can skip chmod() if mkdir() succeeded, but we must explicitly 182228753Smm * chmod() if we're trying to create a directory that already exists 183228753Smm * (mkdir() failed) or if we're restoring a symlink. Similarly, we 184228753Smm * need to verify UID/GID before trying to restore SUID/SGID bits; 185228753Smm * that verification can occur explicitly through a stat() call or 186228753Smm * implicitly because of a successful chown() call. 187228753Smm */ 188228753Smm#define TODO_MODE_FORCE 0x40000000 189228753Smm#define TODO_MODE_BASE 0x20000000 190228753Smm#define TODO_SUID 0x10000000 191228753Smm#define TODO_SUID_CHECK 0x08000000 192228753Smm#define TODO_SGID 0x04000000 193228753Smm#define TODO_SGID_CHECK 0x02000000 194248616Smm#define TODO_APPLEDOUBLE 0x01000000 195228753Smm#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID) 196228753Smm#define TODO_TIMES ARCHIVE_EXTRACT_TIME 197228753Smm#define TODO_OWNER ARCHIVE_EXTRACT_OWNER 198228753Smm#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS 199228753Smm#define TODO_ACLS ARCHIVE_EXTRACT_ACL 200228753Smm#define TODO_XATTR ARCHIVE_EXTRACT_XATTR 201231200Smm#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA 202248616Smm#define TODO_HFS_COMPRESSION ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED 203228753Smm 204228753Smmstruct archive_write_disk { 205228753Smm struct archive archive; 206228753Smm 207228753Smm mode_t user_umask; 208228753Smm struct fixup_entry *fixup_list; 209228753Smm struct fixup_entry *current_fixup; 210231200Smm int64_t user_uid; 211231200Smm int skip_file_set; 212238856Smm int64_t skip_file_dev; 213238856Smm int64_t skip_file_ino; 214228753Smm time_t start_time; 215228753Smm 216231200Smm int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid); 217228753Smm void (*cleanup_gid)(void *private); 218228753Smm void *lookup_gid_data; 219231200Smm int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid); 220228753Smm void (*cleanup_uid)(void *private); 221228753Smm void *lookup_uid_data; 222228753Smm 223228753Smm /* 224228753Smm * Full path of last file to satisfy symlink checks. 225228753Smm */ 226228753Smm struct archive_string path_safe; 227228753Smm 228228753Smm /* 229228753Smm * Cached stat data from disk for the current entry. 230228753Smm * If this is valid, pst points to st. Otherwise, 231228753Smm * pst is null. 232228753Smm */ 233228753Smm struct stat st; 234228753Smm struct stat *pst; 235228753Smm 236228753Smm /* Information about the object being restored right now. */ 237228753Smm struct archive_entry *entry; /* Entry being extracted. */ 238228753Smm char *name; /* Name of entry, possibly edited. */ 239228753Smm struct archive_string _name_data; /* backing store for 'name' */ 240228753Smm /* Tasks remaining for this object. */ 241228753Smm int todo; 242228753Smm /* Tasks deferred until end-of-archive. */ 243228753Smm int deferred; 244228753Smm /* Options requested by the client. */ 245228753Smm int flags; 246228753Smm /* Handle for the file we're restoring. */ 247228753Smm int fd; 248228753Smm /* Current offset for writing data to the file. */ 249231200Smm int64_t offset; 250228753Smm /* Last offset actually written to disk. */ 251231200Smm int64_t fd_offset; 252231200Smm /* Total bytes actually written to files. */ 253231200Smm int64_t total_bytes_written; 254228753Smm /* Maximum size of file, -1 if unknown. */ 255231200Smm int64_t filesize; 256228753Smm /* Dir we were in before this restore; only for deep paths. */ 257228753Smm int restore_pwd; 258228753Smm /* Mode we should use for this entry; affected by _PERM and umask. */ 259228753Smm mode_t mode; 260228753Smm /* UID/GID to use in restoring this entry. */ 261231200Smm int64_t uid; 262231200Smm int64_t gid; 263248616Smm /* 264248616Smm * HFS+ Compression. 265248616Smm */ 266248616Smm /* Xattr "com.apple.decmpfs". */ 267248616Smm uint32_t decmpfs_attr_size; 268248616Smm unsigned char *decmpfs_header_p; 269248616Smm /* ResourceFork set options used for fsetxattr. */ 270248616Smm int rsrc_xattr_options; 271248616Smm /* Xattr "com.apple.ResourceFork". */ 272248616Smm unsigned char *resource_fork; 273248616Smm size_t resource_fork_allocated_size; 274248616Smm unsigned int decmpfs_block_count; 275248616Smm uint32_t *decmpfs_block_info; 276248616Smm /* Buffer for compressed data. */ 277248616Smm unsigned char *compressed_buffer; 278248616Smm size_t compressed_buffer_size; 279248616Smm size_t compressed_buffer_remaining; 280248616Smm /* The offset of the ResourceFork where compressed data will 281248616Smm * be placed. */ 282248616Smm uint32_t compressed_rsrc_position; 283248616Smm uint32_t compressed_rsrc_position_v; 284248616Smm /* Buffer for uncompressed data. */ 285248616Smm char *uncompressed_buffer; 286248616Smm size_t block_remaining_bytes; 287248616Smm size_t file_remaining_bytes; 288248616Smm#ifdef HAVE_ZLIB_H 289248616Smm z_stream stream; 290248616Smm int stream_valid; 291248616Smm int decmpfs_compression_level; 292248616Smm#endif 293228753Smm}; 294228753Smm 295228753Smm/* 296228753Smm * Default mode for dirs created automatically (will be modified by umask). 297231200Smm * Note that POSIX specifies 0777 for implicitly-created dirs, "modified 298228753Smm * by the process' file creation mask." 299228753Smm */ 300228753Smm#define DEFAULT_DIR_MODE 0777 301228753Smm/* 302228753Smm * Dir modes are restored in two steps: During the extraction, the permissions 303228753Smm * in the archive are modified to match the following limits. During 304228753Smm * the post-extract fixup pass, the permissions from the archive are 305228753Smm * applied. 306228753Smm */ 307228753Smm#define MINIMUM_DIR_MODE 0700 308228753Smm#define MAXIMUM_DIR_MODE 0775 309228753Smm 310248616Smm/* 311248616Smm * Maxinum uncompressed size of a decmpfs block. 312248616Smm */ 313248616Smm#define MAX_DECMPFS_BLOCK_SIZE (64 * 1024) 314248616Smm/* 315248616Smm * HFS+ compression type. 316248616Smm */ 317248616Smm#define CMP_XATTR 3/* Compressed data in xattr. */ 318248616Smm#define CMP_RESOURCE_FORK 4/* Compressed data in resource fork. */ 319248616Smm/* 320248616Smm * HFS+ compression resource fork. 321248616Smm */ 322248616Smm#define RSRC_H_SIZE 260 /* Base size of Resource fork header. */ 323248616Smm#define RSRC_F_SIZE 50 /* Size of Resource fork footer. */ 324248616Smm/* Size to write compressed data to resource fork. */ 325248616Smm#define COMPRESSED_W_SIZE (64 * 1024) 326248616Smm/* decmpfs difinitions. */ 327248616Smm#define MAX_DECMPFS_XATTR_SIZE 3802 328248616Smm#ifndef DECMPFS_XATTR_NAME 329248616Smm#define DECMPFS_XATTR_NAME "com.apple.decmpfs" 330248616Smm#endif 331248616Smm#define DECMPFS_MAGIC 0x636d7066 332248616Smm#define DECMPFS_COMPRESSION_MAGIC 0 333248616Smm#define DECMPFS_COMPRESSION_TYPE 4 334248616Smm#define DECMPFS_UNCOMPRESSED_SIZE 8 335248616Smm#define DECMPFS_HEADER_SIZE 16 336248616Smm 337248616Smm#define HFS_BLOCKS(s) ((s) >> 12) 338248616Smm 339306941Sdelphijstatic int check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags); 340228753Smmstatic int check_symlinks(struct archive_write_disk *); 341228753Smmstatic int create_filesystem_object(struct archive_write_disk *); 342228753Smmstatic struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname); 343231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX) 344228753Smmstatic void edit_deep_directories(struct archive_write_disk *ad); 345228753Smm#endif 346306941Sdelphijstatic int cleanup_pathname_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags); 347228753Smmstatic int cleanup_pathname(struct archive_write_disk *); 348228753Smmstatic int create_dir(struct archive_write_disk *, char *); 349228753Smmstatic int create_parent_dir(struct archive_write_disk *, char *); 350248616Smmstatic ssize_t hfs_write_data_block(struct archive_write_disk *, 351248616Smm const char *, size_t); 352248616Smmstatic int fixup_appledouble(struct archive_write_disk *, const char *); 353228753Smmstatic int older(struct stat *, struct archive_entry *); 354228753Smmstatic int restore_entry(struct archive_write_disk *); 355231200Smmstatic int set_mac_metadata(struct archive_write_disk *, const char *, 356231200Smm const void *, size_t); 357228753Smmstatic int set_xattrs(struct archive_write_disk *); 358228753Smmstatic int set_fflags(struct archive_write_disk *); 359228753Smmstatic int set_fflags_platform(struct archive_write_disk *, int fd, 360228753Smm const char *name, mode_t mode, 361228753Smm unsigned long fflags_set, unsigned long fflags_clear); 362228753Smmstatic int set_ownership(struct archive_write_disk *); 363228753Smmstatic int set_mode(struct archive_write_disk *, int mode); 364228753Smmstatic int set_time(int, int, const char *, time_t, long, time_t, long); 365231200Smmstatic int set_times(struct archive_write_disk *, int, int, const char *, 366231200Smm time_t, long, time_t, long, time_t, long, time_t, long); 367231200Smmstatic int set_times_from_entry(struct archive_write_disk *); 368228753Smmstatic struct fixup_entry *sort_dir_list(struct fixup_entry *p); 369228753Smmstatic ssize_t write_data_block(struct archive_write_disk *, 370228753Smm const char *, size_t); 371228753Smm 372228753Smmstatic struct archive_vtable *archive_write_disk_vtable(void); 373228753Smm 374231200Smmstatic int _archive_write_disk_close(struct archive *); 375231200Smmstatic int _archive_write_disk_free(struct archive *); 376231200Smmstatic int _archive_write_disk_header(struct archive *, struct archive_entry *); 377231200Smmstatic int64_t _archive_write_disk_filter_bytes(struct archive *, int); 378231200Smmstatic int _archive_write_disk_finish_entry(struct archive *); 379231200Smmstatic ssize_t _archive_write_disk_data(struct archive *, const void *, size_t); 380231200Smmstatic ssize_t _archive_write_disk_data_block(struct archive *, const void *, size_t, int64_t); 381228753Smm 382228753Smmstatic int 383231200Smmlazy_stat(struct archive_write_disk *a) 384228753Smm{ 385228753Smm if (a->pst != NULL) { 386228753Smm /* Already have stat() data available. */ 387228753Smm return (ARCHIVE_OK); 388228753Smm } 389228753Smm#ifdef HAVE_FSTAT 390228753Smm if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) { 391228753Smm a->pst = &a->st; 392228753Smm return (ARCHIVE_OK); 393228753Smm } 394228753Smm#endif 395228753Smm /* 396228753Smm * XXX At this point, symlinks should not be hit, otherwise 397231200Smm * XXX a race occurred. Do we want to check explicitly for that? 398228753Smm */ 399228753Smm if (lstat(a->name, &a->st) == 0) { 400228753Smm a->pst = &a->st; 401228753Smm return (ARCHIVE_OK); 402228753Smm } 403228753Smm archive_set_error(&a->archive, errno, "Couldn't stat file"); 404228753Smm return (ARCHIVE_WARN); 405228753Smm} 406228753Smm 407228753Smmstatic struct archive_vtable * 408228753Smmarchive_write_disk_vtable(void) 409228753Smm{ 410228753Smm static struct archive_vtable av; 411228753Smm static int inited = 0; 412228753Smm 413228753Smm if (!inited) { 414231200Smm av.archive_close = _archive_write_disk_close; 415231200Smm av.archive_filter_bytes = _archive_write_disk_filter_bytes; 416231200Smm av.archive_free = _archive_write_disk_free; 417231200Smm av.archive_write_header = _archive_write_disk_header; 418231200Smm av.archive_write_finish_entry 419231200Smm = _archive_write_disk_finish_entry; 420231200Smm av.archive_write_data = _archive_write_disk_data; 421231200Smm av.archive_write_data_block = _archive_write_disk_data_block; 422231200Smm inited = 1; 423228753Smm } 424228753Smm return (&av); 425228753Smm} 426228753Smm 427231200Smmstatic int64_t 428231200Smm_archive_write_disk_filter_bytes(struct archive *_a, int n) 429231200Smm{ 430231200Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 431231200Smm (void)n; /* UNUSED */ 432231200Smm if (n == -1 || n == 0) 433231200Smm return (a->total_bytes_written); 434231200Smm return (-1); 435231200Smm} 436228753Smm 437231200Smm 438228753Smmint 439228753Smmarchive_write_disk_set_options(struct archive *_a, int flags) 440228753Smm{ 441228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 442228753Smm 443228753Smm a->flags = flags; 444228753Smm return (ARCHIVE_OK); 445228753Smm} 446228753Smm 447228753Smm 448228753Smm/* 449228753Smm * Extract this entry to disk. 450228753Smm * 451228753Smm * TODO: Validate hardlinks. According to the standards, we're 452228753Smm * supposed to check each extracted hardlink and squawk if it refers 453228753Smm * to a file that we didn't restore. I'm not entirely convinced this 454228753Smm * is a good idea, but more importantly: Is there any way to validate 455228753Smm * hardlinks without keeping a complete list of filenames from the 456228753Smm * entire archive?? Ugh. 457228753Smm * 458228753Smm */ 459228753Smmstatic int 460231200Smm_archive_write_disk_header(struct archive *_a, struct archive_entry *entry) 461228753Smm{ 462228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 463228753Smm struct fixup_entry *fe; 464228753Smm int ret, r; 465228753Smm 466231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 467228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 468228753Smm "archive_write_disk_header"); 469228753Smm archive_clear_error(&a->archive); 470228753Smm if (a->archive.state & ARCHIVE_STATE_DATA) { 471231200Smm r = _archive_write_disk_finish_entry(&a->archive); 472228753Smm if (r == ARCHIVE_FATAL) 473228753Smm return (r); 474228753Smm } 475228753Smm 476228753Smm /* Set up for this particular entry. */ 477228753Smm a->pst = NULL; 478228753Smm a->current_fixup = NULL; 479228753Smm a->deferred = 0; 480228753Smm if (a->entry) { 481228753Smm archive_entry_free(a->entry); 482228753Smm a->entry = NULL; 483228753Smm } 484228753Smm a->entry = archive_entry_clone(entry); 485228753Smm a->fd = -1; 486228753Smm a->fd_offset = 0; 487228753Smm a->offset = 0; 488231200Smm a->restore_pwd = -1; 489228753Smm a->uid = a->user_uid; 490228753Smm a->mode = archive_entry_mode(a->entry); 491228753Smm if (archive_entry_size_is_set(a->entry)) 492228753Smm a->filesize = archive_entry_size(a->entry); 493228753Smm else 494228753Smm a->filesize = -1; 495228753Smm archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry)); 496228753Smm a->name = a->_name_data.s; 497228753Smm archive_clear_error(&a->archive); 498228753Smm 499228753Smm /* 500228753Smm * Clean up the requested path. This is necessary for correct 501228753Smm * dir restores; the dir restore logic otherwise gets messed 502228753Smm * up by nonsense like "dir/.". 503228753Smm */ 504228753Smm ret = cleanup_pathname(a); 505228753Smm if (ret != ARCHIVE_OK) 506228753Smm return (ret); 507228753Smm 508228753Smm /* 509231200Smm * Query the umask so we get predictable mode settings. 510228753Smm * This gets done on every call to _write_header in case the 511228753Smm * user edits their umask during the extraction for some 512231200Smm * reason. 513228753Smm */ 514231200Smm umask(a->user_umask = umask(0)); 515228753Smm 516228753Smm /* Figure out what we need to do for this entry. */ 517228753Smm a->todo = TODO_MODE_BASE; 518228753Smm if (a->flags & ARCHIVE_EXTRACT_PERM) { 519228753Smm a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ 520228753Smm /* 521228753Smm * SGID requires an extra "check" step because we 522228753Smm * cannot easily predict the GID that the system will 523228753Smm * assign. (Different systems assign GIDs to files 524228753Smm * based on a variety of criteria, including process 525228753Smm * credentials and the gid of the enclosing 526228753Smm * directory.) We can only restore the SGID bit if 527228753Smm * the file has the right GID, and we only know the 528228753Smm * GID if we either set it (see set_ownership) or if 529228753Smm * we've actually called stat() on the file after it 530228753Smm * was restored. Since there are several places at 531228753Smm * which we might verify the GID, we need a TODO bit 532228753Smm * to keep track. 533228753Smm */ 534228753Smm if (a->mode & S_ISGID) 535228753Smm a->todo |= TODO_SGID | TODO_SGID_CHECK; 536228753Smm /* 537228753Smm * Verifying the SUID is simpler, but can still be 538228753Smm * done in multiple ways, hence the separate "check" bit. 539228753Smm */ 540228753Smm if (a->mode & S_ISUID) 541228753Smm a->todo |= TODO_SUID | TODO_SUID_CHECK; 542228753Smm } else { 543228753Smm /* 544228753Smm * User didn't request full permissions, so don't 545228753Smm * restore SUID, SGID bits and obey umask. 546228753Smm */ 547228753Smm a->mode &= ~S_ISUID; 548228753Smm a->mode &= ~S_ISGID; 549228753Smm a->mode &= ~S_ISVTX; 550228753Smm a->mode &= ~a->user_umask; 551228753Smm } 552228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) 553228753Smm a->todo |= TODO_OWNER; 554228753Smm if (a->flags & ARCHIVE_EXTRACT_TIME) 555228753Smm a->todo |= TODO_TIMES; 556231200Smm if (a->flags & ARCHIVE_EXTRACT_ACL) { 557231200Smm if (archive_entry_filetype(a->entry) == AE_IFDIR) 558231200Smm a->deferred |= TODO_ACLS; 559231200Smm else 560231200Smm a->todo |= TODO_ACLS; 561231200Smm } 562231200Smm if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) { 563231200Smm if (archive_entry_filetype(a->entry) == AE_IFDIR) 564231200Smm a->deferred |= TODO_MAC_METADATA; 565231200Smm else 566231200Smm a->todo |= TODO_MAC_METADATA; 567231200Smm } 568248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) 569248616Smm if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) { 570248616Smm unsigned long set, clear; 571248616Smm archive_entry_fflags(a->entry, &set, &clear); 572248616Smm if ((set & ~clear) & UF_COMPRESSED) { 573248616Smm a->todo |= TODO_HFS_COMPRESSION; 574248616Smm a->decmpfs_block_count = (unsigned)-1; 575248616Smm } 576248616Smm } 577248616Smm if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 && 578248616Smm (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) { 579248616Smm a->todo |= TODO_HFS_COMPRESSION; 580248616Smm a->decmpfs_block_count = (unsigned)-1; 581248616Smm } 582248616Smm { 583248616Smm const char *p; 584248616Smm 585248616Smm /* Check if the current file name is a type of the 586248616Smm * resource fork file. */ 587248616Smm p = strrchr(a->name, '/'); 588248616Smm if (p == NULL) 589248616Smm p = a->name; 590248616Smm else 591248616Smm p++; 592248616Smm if (p[0] == '.' && p[1] == '_') { 593248616Smm /* Do not compress "._XXX" files. */ 594248616Smm a->todo &= ~TODO_HFS_COMPRESSION; 595248616Smm if (a->filesize > 0) 596248616Smm a->todo |= TODO_APPLEDOUBLE; 597248616Smm } 598248616Smm } 599248616Smm#endif 600248616Smm 601228753Smm if (a->flags & ARCHIVE_EXTRACT_XATTR) 602228753Smm a->todo |= TODO_XATTR; 603228753Smm if (a->flags & ARCHIVE_EXTRACT_FFLAGS) 604228753Smm a->todo |= TODO_FFLAGS; 605228753Smm if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { 606228753Smm ret = check_symlinks(a); 607228753Smm if (ret != ARCHIVE_OK) 608231200Smm return (ret); 609228753Smm } 610231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX) 611228753Smm /* If path exceeds PATH_MAX, shorten the path. */ 612228753Smm edit_deep_directories(a); 613228753Smm#endif 614228753Smm 615228753Smm ret = restore_entry(a); 616228753Smm 617248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) 618228753Smm /* 619248616Smm * Check if the filesystem the file is restoring on supports 620248616Smm * HFS+ Compression. If not, cancel HFS+ Compression. 621248616Smm */ 622248616Smm if (a->todo | TODO_HFS_COMPRESSION) { 623248616Smm /* 624248616Smm * NOTE: UF_COMPRESSED is ignored even if the filesystem 625248616Smm * supports HFS+ Compression because the file should 626248616Smm * have at least an extended attriute "com.apple.decmpfs" 627248616Smm * before the flag is set to indicate that the file have 628248616Smm * been compressed. If hte filesystem does not support 629248616Smm * HFS+ Compression the system call will fail. 630248616Smm */ 631248616Smm if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0) 632248616Smm a->todo &= ~TODO_HFS_COMPRESSION; 633248616Smm } 634248616Smm#endif 635248616Smm 636248616Smm /* 637228753Smm * TODO: There are rumours that some extended attributes must 638228753Smm * be restored before file data is written. If this is true, 639228753Smm * then we either need to write all extended attributes both 640228753Smm * before and after restoring the data, or find some rule for 641228753Smm * determining which must go first and which last. Due to the 642228753Smm * many ways people are using xattrs, this may prove to be an 643228753Smm * intractable problem. 644228753Smm */ 645228753Smm 646228753Smm#ifdef HAVE_FCHDIR 647228753Smm /* If we changed directory above, restore it here. */ 648228753Smm if (a->restore_pwd >= 0) { 649228753Smm r = fchdir(a->restore_pwd); 650228753Smm if (r != 0) { 651228753Smm archive_set_error(&a->archive, errno, "chdir() failure"); 652228753Smm ret = ARCHIVE_FATAL; 653228753Smm } 654228753Smm close(a->restore_pwd); 655228753Smm a->restore_pwd = -1; 656228753Smm } 657228753Smm#endif 658228753Smm 659228753Smm /* 660228753Smm * Fixup uses the unedited pathname from archive_entry_pathname(), 661228753Smm * because it is relative to the base dir and the edited path 662228753Smm * might be relative to some intermediate dir as a result of the 663228753Smm * deep restore logic. 664228753Smm */ 665228753Smm if (a->deferred & TODO_MODE) { 666228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 667248616Smm if (fe == NULL) 668248616Smm return (ARCHIVE_FATAL); 669228753Smm fe->fixup |= TODO_MODE_BASE; 670228753Smm fe->mode = a->mode; 671228753Smm } 672228753Smm 673228753Smm if ((a->deferred & TODO_TIMES) 674228753Smm && (archive_entry_mtime_is_set(entry) 675228753Smm || archive_entry_atime_is_set(entry))) { 676228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 677248616Smm if (fe == NULL) 678248616Smm return (ARCHIVE_FATAL); 679231200Smm fe->mode = a->mode; 680228753Smm fe->fixup |= TODO_TIMES; 681228753Smm if (archive_entry_atime_is_set(entry)) { 682228753Smm fe->atime = archive_entry_atime(entry); 683228753Smm fe->atime_nanos = archive_entry_atime_nsec(entry); 684228753Smm } else { 685228753Smm /* If atime is unset, use start time. */ 686228753Smm fe->atime = a->start_time; 687228753Smm fe->atime_nanos = 0; 688228753Smm } 689228753Smm if (archive_entry_mtime_is_set(entry)) { 690228753Smm fe->mtime = archive_entry_mtime(entry); 691228753Smm fe->mtime_nanos = archive_entry_mtime_nsec(entry); 692228753Smm } else { 693228753Smm /* If mtime is unset, use start time. */ 694228753Smm fe->mtime = a->start_time; 695228753Smm fe->mtime_nanos = 0; 696228753Smm } 697228753Smm if (archive_entry_birthtime_is_set(entry)) { 698228753Smm fe->birthtime = archive_entry_birthtime(entry); 699228753Smm fe->birthtime_nanos = archive_entry_birthtime_nsec(entry); 700228753Smm } else { 701228753Smm /* If birthtime is unset, use mtime. */ 702228753Smm fe->birthtime = fe->mtime; 703228753Smm fe->birthtime_nanos = fe->mtime_nanos; 704228753Smm } 705228753Smm } 706228753Smm 707231200Smm if (a->deferred & TODO_ACLS) { 708231200Smm fe = current_fixup(a, archive_entry_pathname(entry)); 709248616Smm if (fe == NULL) 710248616Smm return (ARCHIVE_FATAL); 711238909Smm fe->fixup |= TODO_ACLS; 712231200Smm archive_acl_copy(&fe->acl, archive_entry_acl(entry)); 713231200Smm } 714231200Smm 715231200Smm if (a->deferred & TODO_MAC_METADATA) { 716231200Smm const void *metadata; 717231200Smm size_t metadata_size; 718231200Smm metadata = archive_entry_mac_metadata(a->entry, &metadata_size); 719231200Smm if (metadata != NULL && metadata_size > 0) { 720231200Smm fe = current_fixup(a, archive_entry_pathname(entry)); 721248616Smm if (fe == NULL) 722248616Smm return (ARCHIVE_FATAL); 723231200Smm fe->mac_metadata = malloc(metadata_size); 724231200Smm if (fe->mac_metadata != NULL) { 725231200Smm memcpy(fe->mac_metadata, metadata, metadata_size); 726231200Smm fe->mac_metadata_size = metadata_size; 727231200Smm fe->fixup |= TODO_MAC_METADATA; 728231200Smm } 729231200Smm } 730231200Smm } 731231200Smm 732228753Smm if (a->deferred & TODO_FFLAGS) { 733228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 734248616Smm if (fe == NULL) 735248616Smm return (ARCHIVE_FATAL); 736228753Smm fe->fixup |= TODO_FFLAGS; 737228753Smm /* TODO: Complete this.. defer fflags from below. */ 738228753Smm } 739228753Smm 740228753Smm /* We've created the object and are ready to pour data into it. */ 741228753Smm if (ret >= ARCHIVE_WARN) 742228753Smm a->archive.state = ARCHIVE_STATE_DATA; 743228753Smm /* 744228753Smm * If it's not open, tell our client not to try writing. 745228753Smm * In particular, dirs, links, etc, don't get written to. 746228753Smm */ 747228753Smm if (a->fd < 0) { 748228753Smm archive_entry_set_size(entry, 0); 749228753Smm a->filesize = 0; 750228753Smm } 751228753Smm 752228753Smm return (ret); 753228753Smm} 754228753Smm 755228753Smmint 756231200Smmarchive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i) 757228753Smm{ 758228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 759231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 760228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file"); 761231200Smm a->skip_file_set = 1; 762228753Smm a->skip_file_dev = d; 763228753Smm a->skip_file_ino = i; 764228753Smm return (ARCHIVE_OK); 765228753Smm} 766228753Smm 767228753Smmstatic ssize_t 768228753Smmwrite_data_block(struct archive_write_disk *a, const char *buff, size_t size) 769228753Smm{ 770228753Smm uint64_t start_size = size; 771228753Smm ssize_t bytes_written = 0; 772228753Smm ssize_t block_size = 0, bytes_to_write; 773228753Smm 774228753Smm if (size == 0) 775228753Smm return (ARCHIVE_OK); 776228753Smm 777228753Smm if (a->filesize == 0 || a->fd < 0) { 778228753Smm archive_set_error(&a->archive, 0, 779228753Smm "Attempt to write to an empty file"); 780228753Smm return (ARCHIVE_WARN); 781228753Smm } 782228753Smm 783228753Smm if (a->flags & ARCHIVE_EXTRACT_SPARSE) { 784228753Smm#if HAVE_STRUCT_STAT_ST_BLKSIZE 785228753Smm int r; 786231200Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 787228753Smm return (r); 788228753Smm block_size = a->pst->st_blksize; 789228753Smm#else 790228753Smm /* XXX TODO XXX Is there a more appropriate choice here ? */ 791228753Smm /* This needn't match the filesystem allocation size. */ 792228753Smm block_size = 16*1024; 793228753Smm#endif 794228753Smm } 795228753Smm 796228753Smm /* If this write would run beyond the file size, truncate it. */ 797231200Smm if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) 798228753Smm start_size = size = (size_t)(a->filesize - a->offset); 799228753Smm 800228753Smm /* Write the data. */ 801228753Smm while (size > 0) { 802228753Smm if (block_size == 0) { 803228753Smm bytes_to_write = size; 804228753Smm } else { 805228753Smm /* We're sparsifying the file. */ 806228753Smm const char *p, *end; 807231200Smm int64_t block_end; 808228753Smm 809228753Smm /* Skip leading zero bytes. */ 810228753Smm for (p = buff, end = buff + size; p < end; ++p) { 811228753Smm if (*p != '\0') 812228753Smm break; 813228753Smm } 814228753Smm a->offset += p - buff; 815228753Smm size -= p - buff; 816228753Smm buff = p; 817228753Smm if (size == 0) 818228753Smm break; 819228753Smm 820228753Smm /* Calculate next block boundary after offset. */ 821228753Smm block_end 822228753Smm = (a->offset / block_size + 1) * block_size; 823228753Smm 824228753Smm /* If the adjusted write would cross block boundary, 825228753Smm * truncate it to the block boundary. */ 826228753Smm bytes_to_write = size; 827228753Smm if (a->offset + bytes_to_write > block_end) 828228753Smm bytes_to_write = block_end - a->offset; 829228753Smm } 830228753Smm /* Seek if necessary to the specified offset. */ 831228753Smm if (a->offset != a->fd_offset) { 832228753Smm if (lseek(a->fd, a->offset, SEEK_SET) < 0) { 833228753Smm archive_set_error(&a->archive, errno, 834228753Smm "Seek failed"); 835228753Smm return (ARCHIVE_FATAL); 836228753Smm } 837228753Smm a->fd_offset = a->offset; 838231200Smm } 839228753Smm bytes_written = write(a->fd, buff, bytes_to_write); 840228753Smm if (bytes_written < 0) { 841228753Smm archive_set_error(&a->archive, errno, "Write failed"); 842228753Smm return (ARCHIVE_WARN); 843228753Smm } 844228753Smm buff += bytes_written; 845228753Smm size -= bytes_written; 846231200Smm a->total_bytes_written += bytes_written; 847228753Smm a->offset += bytes_written; 848228753Smm a->fd_offset = a->offset; 849228753Smm } 850228753Smm return (start_size - size); 851228753Smm} 852228753Smm 853248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ 854248616Smm && defined(HAVE_ZLIB_H) 855248616Smm 856248616Smm/* 857248616Smm * Set UF_COMPRESSED file flag. 858248616Smm * This have to be called after hfs_write_decmpfs() because if the 859248616Smm * file does not have "com.apple.decmpfs" xattr the flag is ignored. 860248616Smm */ 861248616Smmstatic int 862248616Smmhfs_set_compressed_fflag(struct archive_write_disk *a) 863248616Smm{ 864248616Smm int r; 865248616Smm 866248616Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 867248616Smm return (r); 868248616Smm 869248616Smm a->st.st_flags |= UF_COMPRESSED; 870248616Smm if (fchflags(a->fd, a->st.st_flags) != 0) { 871248616Smm archive_set_error(&a->archive, errno, 872248616Smm "Failed to set UF_COMPRESSED file flag"); 873248616Smm return (ARCHIVE_WARN); 874248616Smm } 875248616Smm return (ARCHIVE_OK); 876248616Smm} 877248616Smm 878248616Smm/* 879248616Smm * HFS+ Compression decmpfs 880248616Smm * 881248616Smm * +------------------------------+ +0 882248616Smm * | Magic(LE 4 bytes) | 883248616Smm * +------------------------------+ 884248616Smm * | Type(LE 4 bytes) | 885248616Smm * +------------------------------+ 886248616Smm * | Uncompressed size(LE 8 bytes)| 887248616Smm * +------------------------------+ +16 888248616Smm * | | 889248616Smm * | Compressed data | 890248616Smm * | (Placed only if Type == 3) | 891248616Smm * | | 892248616Smm * +------------------------------+ +3802 = MAX_DECMPFS_XATTR_SIZE 893248616Smm * 894248616Smm * Type is 3: decmpfs has compressed data. 895248616Smm * Type is 4: Resource Fork has compressed data. 896248616Smm */ 897248616Smm/* 898248616Smm * Write "com.apple.decmpfs" 899248616Smm */ 900248616Smmstatic int 901248616Smmhfs_write_decmpfs(struct archive_write_disk *a) 902248616Smm{ 903248616Smm int r; 904248616Smm uint32_t compression_type; 905248616Smm 906248616Smm r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p, 907248616Smm a->decmpfs_attr_size, 0, 0); 908248616Smm if (r < 0) { 909248616Smm archive_set_error(&a->archive, errno, 910248616Smm "Cannot restore xattr:%s", DECMPFS_XATTR_NAME); 911248616Smm compression_type = archive_le32dec( 912248616Smm &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]); 913248616Smm if (compression_type == CMP_RESOURCE_FORK) 914248616Smm fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 915248616Smm XATTR_SHOWCOMPRESSION); 916248616Smm return (ARCHIVE_WARN); 917248616Smm } 918248616Smm return (ARCHIVE_OK); 919248616Smm} 920248616Smm 921248616Smm/* 922248616Smm * HFS+ Compression Resource Fork 923248616Smm * 924248616Smm * +-----------------------------+ 925248616Smm * | Header(260 bytes) | 926248616Smm * +-----------------------------+ 927248616Smm * | Block count(LE 4 bytes) | 928248616Smm * +-----------------------------+ --+ 929248616Smm * +-- | Offset (LE 4 bytes) | | 930248616Smm * | | [distance from Block count] | | Block 0 931248616Smm * | +-----------------------------+ | 932248616Smm * | | Compressed size(LE 4 bytes) | | 933248616Smm * | +-----------------------------+ --+ 934248616Smm * | | | 935248616Smm * | | .................. | 936248616Smm * | | | 937248616Smm * | +-----------------------------+ --+ 938248616Smm * | | Offset (LE 4 bytes) | | 939248616Smm * | +-----------------------------+ | Block (Block count -1) 940248616Smm * | | Compressed size(LE 4 bytes) | | 941248616Smm * +-> +-----------------------------+ --+ 942248616Smm * | Compressed data(n bytes) | Block 0 943248616Smm * +-----------------------------+ 944248616Smm * | | 945248616Smm * | .................. | 946248616Smm * | | 947248616Smm * +-----------------------------+ 948248616Smm * | Compressed data(n bytes) | Block (Block count -1) 949248616Smm * +-----------------------------+ 950248616Smm * | Footer(50 bytes) | 951248616Smm * +-----------------------------+ 952248616Smm * 953248616Smm */ 954248616Smm/* 955248616Smm * Write the header of "com.apple.ResourceFork" 956248616Smm */ 957248616Smmstatic int 958248616Smmhfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff, 959248616Smm size_t bytes, uint32_t position) 960248616Smm{ 961248616Smm int ret; 962248616Smm 963248616Smm ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes, 964248616Smm position, a->rsrc_xattr_options); 965248616Smm if (ret < 0) { 966248616Smm archive_set_error(&a->archive, errno, 967248616Smm "Cannot restore xattr: %s at %u pos %u bytes", 968248616Smm XATTR_RESOURCEFORK_NAME, 969248616Smm (unsigned)position, 970248616Smm (unsigned)bytes); 971248616Smm return (ARCHIVE_WARN); 972248616Smm } 973248616Smm a->rsrc_xattr_options &= ~XATTR_CREATE; 974248616Smm return (ARCHIVE_OK); 975248616Smm} 976248616Smm 977248616Smmstatic int 978248616Smmhfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed) 979248616Smm{ 980248616Smm int ret; 981248616Smm 982248616Smm ret = hfs_write_resource_fork(a, a->compressed_buffer, 983248616Smm bytes_compressed, a->compressed_rsrc_position); 984248616Smm if (ret == ARCHIVE_OK) 985248616Smm a->compressed_rsrc_position += bytes_compressed; 986248616Smm return (ret); 987248616Smm} 988248616Smm 989248616Smmstatic int 990248616Smmhfs_write_resource_fork_header(struct archive_write_disk *a) 991248616Smm{ 992248616Smm unsigned char *buff; 993248616Smm uint32_t rsrc_bytes; 994248616Smm uint32_t rsrc_header_bytes; 995248616Smm 996248616Smm /* 997248616Smm * Write resource fork header + block info. 998248616Smm */ 999248616Smm buff = a->resource_fork; 1000248616Smm rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE; 1001248616Smm rsrc_header_bytes = 1002248616Smm RSRC_H_SIZE + /* Header base size. */ 1003248616Smm 4 + /* Block count. */ 1004248616Smm (a->decmpfs_block_count * 8);/* Block info */ 1005248616Smm archive_be32enc(buff, 0x100); 1006248616Smm archive_be32enc(buff + 4, rsrc_bytes); 1007248616Smm archive_be32enc(buff + 8, rsrc_bytes - 256); 1008248616Smm archive_be32enc(buff + 12, 0x32); 1009248616Smm memset(buff + 16, 0, 240); 1010248616Smm archive_be32enc(buff + 256, rsrc_bytes - 260); 1011248616Smm return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0); 1012248616Smm} 1013248616Smm 1014248616Smmstatic size_t 1015248616Smmhfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size) 1016248616Smm{ 1017248616Smm static const char rsrc_footer[RSRC_F_SIZE] = { 1018248616Smm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1019248616Smm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1020248616Smm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1021248616Smm 0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c', 'm', 1022248616Smm 'p', 'f', 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 1023248616Smm 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1024248616Smm 0x00, 0x00 1025248616Smm }; 1026248616Smm if (buff_size < sizeof(rsrc_footer)) 1027248616Smm return (0); 1028248616Smm memcpy(buff, rsrc_footer, sizeof(rsrc_footer)); 1029248616Smm return (sizeof(rsrc_footer)); 1030248616Smm} 1031248616Smm 1032248616Smmstatic int 1033248616Smmhfs_reset_compressor(struct archive_write_disk *a) 1034248616Smm{ 1035248616Smm int ret; 1036248616Smm 1037248616Smm if (a->stream_valid) 1038248616Smm ret = deflateReset(&a->stream); 1039248616Smm else 1040248616Smm ret = deflateInit(&a->stream, a->decmpfs_compression_level); 1041248616Smm 1042248616Smm if (ret != Z_OK) { 1043248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1044248616Smm "Failed to initialize compressor"); 1045248616Smm return (ARCHIVE_FATAL); 1046248616Smm } else 1047248616Smm a->stream_valid = 1; 1048248616Smm 1049248616Smm return (ARCHIVE_OK); 1050248616Smm} 1051248616Smm 1052248616Smmstatic int 1053248616Smmhfs_decompress(struct archive_write_disk *a) 1054248616Smm{ 1055248616Smm uint32_t *block_info; 1056248616Smm unsigned int block_count; 1057248616Smm uint32_t data_pos, data_size; 1058248616Smm ssize_t r; 1059248616Smm ssize_t bytes_written, bytes_to_write; 1060248616Smm unsigned char *b; 1061248616Smm 1062248616Smm block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE); 1063248616Smm block_count = archive_le32dec(block_info++); 1064248616Smm while (block_count--) { 1065248616Smm data_pos = RSRC_H_SIZE + archive_le32dec(block_info++); 1066248616Smm data_size = archive_le32dec(block_info++); 1067248616Smm r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME, 1068248616Smm a->compressed_buffer, data_size, data_pos, 0); 1069248616Smm if (r != data_size) { 1070248616Smm archive_set_error(&a->archive, 1071248616Smm (r < 0)?errno:ARCHIVE_ERRNO_MISC, 1072248616Smm "Failed to read resource fork"); 1073248616Smm return (ARCHIVE_WARN); 1074248616Smm } 1075248616Smm if (a->compressed_buffer[0] == 0xff) { 1076248616Smm bytes_to_write = data_size -1; 1077248616Smm b = a->compressed_buffer + 1; 1078248616Smm } else { 1079248616Smm uLong dest_len = MAX_DECMPFS_BLOCK_SIZE; 1080248616Smm int zr; 1081248616Smm 1082248616Smm zr = uncompress((Bytef *)a->uncompressed_buffer, 1083248616Smm &dest_len, a->compressed_buffer, data_size); 1084248616Smm if (zr != Z_OK) { 1085248616Smm archive_set_error(&a->archive, 1086248616Smm ARCHIVE_ERRNO_MISC, 1087248616Smm "Failed to decompress resource fork"); 1088248616Smm return (ARCHIVE_WARN); 1089248616Smm } 1090248616Smm bytes_to_write = dest_len; 1091248616Smm b = (unsigned char *)a->uncompressed_buffer; 1092248616Smm } 1093248616Smm do { 1094248616Smm bytes_written = write(a->fd, b, bytes_to_write); 1095248616Smm if (bytes_written < 0) { 1096248616Smm archive_set_error(&a->archive, errno, 1097248616Smm "Write failed"); 1098248616Smm return (ARCHIVE_WARN); 1099248616Smm } 1100248616Smm bytes_to_write -= bytes_written; 1101248616Smm b += bytes_written; 1102248616Smm } while (bytes_to_write > 0); 1103248616Smm } 1104248616Smm r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0); 1105248616Smm if (r == -1) { 1106248616Smm archive_set_error(&a->archive, errno, 1107248616Smm "Failed to remove resource fork"); 1108248616Smm return (ARCHIVE_WARN); 1109248616Smm } 1110248616Smm return (ARCHIVE_OK); 1111248616Smm} 1112248616Smm 1113248616Smmstatic int 1114248616Smmhfs_drive_compressor(struct archive_write_disk *a, const char *buff, 1115248616Smm size_t size) 1116248616Smm{ 1117248616Smm unsigned char *buffer_compressed; 1118248616Smm size_t bytes_compressed; 1119248616Smm size_t bytes_used; 1120248616Smm int ret; 1121248616Smm 1122248616Smm ret = hfs_reset_compressor(a); 1123248616Smm if (ret != ARCHIVE_OK) 1124248616Smm return (ret); 1125248616Smm 1126248616Smm if (a->compressed_buffer == NULL) { 1127248616Smm size_t block_size; 1128248616Smm 1129248616Smm block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE + 1130248616Smm + compressBound(MAX_DECMPFS_BLOCK_SIZE); 1131248616Smm a->compressed_buffer = malloc(block_size); 1132248616Smm if (a->compressed_buffer == NULL) { 1133248616Smm archive_set_error(&a->archive, ENOMEM, 1134248616Smm "Can't allocate memory for Resource Fork"); 1135248616Smm return (ARCHIVE_FATAL); 1136248616Smm } 1137248616Smm a->compressed_buffer_size = block_size; 1138248616Smm a->compressed_buffer_remaining = block_size; 1139248616Smm } 1140248616Smm 1141248616Smm buffer_compressed = a->compressed_buffer + 1142248616Smm a->compressed_buffer_size - a->compressed_buffer_remaining; 1143248616Smm a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff; 1144248616Smm a->stream.avail_in = size; 1145248616Smm a->stream.next_out = buffer_compressed; 1146248616Smm a->stream.avail_out = a->compressed_buffer_remaining; 1147248616Smm do { 1148248616Smm ret = deflate(&a->stream, Z_FINISH); 1149248616Smm switch (ret) { 1150248616Smm case Z_OK: 1151248616Smm case Z_STREAM_END: 1152248616Smm break; 1153248616Smm default: 1154248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1155248616Smm "Failed to compress data"); 1156248616Smm return (ARCHIVE_FAILED); 1157248616Smm } 1158248616Smm } while (ret == Z_OK); 1159248616Smm bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out; 1160248616Smm 1161248616Smm /* 1162248616Smm * If the compressed size is larger than the original size, 1163248616Smm * throw away compressed data, use uncompressed data instead. 1164248616Smm */ 1165248616Smm if (bytes_compressed > size) { 1166248616Smm buffer_compressed[0] = 0xFF;/* uncompressed marker. */ 1167248616Smm memcpy(buffer_compressed + 1, buff, size); 1168248616Smm bytes_compressed = size + 1; 1169248616Smm } 1170248616Smm a->compressed_buffer_remaining -= bytes_compressed; 1171248616Smm 1172248616Smm /* 1173248616Smm * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE 1174248616Smm * and the block count in the file is only one, store compressed 1175248616Smm * data to decmpfs xattr instead of the resource fork. 1176248616Smm */ 1177248616Smm if (a->decmpfs_block_count == 1 && 1178248616Smm (a->decmpfs_attr_size + bytes_compressed) 1179248616Smm <= MAX_DECMPFS_XATTR_SIZE) { 1180248616Smm archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], 1181248616Smm CMP_XATTR); 1182248616Smm memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE, 1183248616Smm buffer_compressed, bytes_compressed); 1184248616Smm a->decmpfs_attr_size += bytes_compressed; 1185248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size; 1186248616Smm /* 1187248616Smm * Finish HFS+ Compression. 1188248616Smm * - Write the decmpfs xattr. 1189248616Smm * - Set the UF_COMPRESSED file flag. 1190248616Smm */ 1191248616Smm ret = hfs_write_decmpfs(a); 1192248616Smm if (ret == ARCHIVE_OK) 1193248616Smm ret = hfs_set_compressed_fflag(a); 1194248616Smm return (ret); 1195248616Smm } 1196248616Smm 1197248616Smm /* Update block info. */ 1198248616Smm archive_le32enc(a->decmpfs_block_info++, 1199248616Smm a->compressed_rsrc_position_v - RSRC_H_SIZE); 1200248616Smm archive_le32enc(a->decmpfs_block_info++, bytes_compressed); 1201248616Smm a->compressed_rsrc_position_v += bytes_compressed; 1202248616Smm 1203248616Smm /* 1204248616Smm * Write the compressed data to the resource fork. 1205248616Smm */ 1206248616Smm bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining; 1207248616Smm while (bytes_used >= COMPRESSED_W_SIZE) { 1208248616Smm ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE); 1209248616Smm if (ret != ARCHIVE_OK) 1210248616Smm return (ret); 1211248616Smm bytes_used -= COMPRESSED_W_SIZE; 1212248616Smm if (bytes_used > COMPRESSED_W_SIZE) 1213248616Smm memmove(a->compressed_buffer, 1214248616Smm a->compressed_buffer + COMPRESSED_W_SIZE, 1215248616Smm bytes_used); 1216248616Smm else 1217248616Smm memcpy(a->compressed_buffer, 1218248616Smm a->compressed_buffer + COMPRESSED_W_SIZE, 1219248616Smm bytes_used); 1220248616Smm } 1221248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used; 1222248616Smm 1223248616Smm /* 1224248616Smm * If the current block is the last block, write the remaining 1225248616Smm * compressed data and the resource fork footer. 1226248616Smm */ 1227248616Smm if (a->file_remaining_bytes == 0) { 1228248616Smm size_t rsrc_size; 1229248616Smm int64_t bk; 1230248616Smm 1231248616Smm /* Append the resource footer. */ 1232248616Smm rsrc_size = hfs_set_resource_fork_footer( 1233248616Smm a->compressed_buffer + bytes_used, 1234248616Smm a->compressed_buffer_remaining); 1235248616Smm ret = hfs_write_compressed_data(a, bytes_used + rsrc_size); 1236248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size; 1237248616Smm 1238248616Smm /* If the compressed size is not enouph smaller than 1239248616Smm * the uncompressed size. cancel HFS+ compression. 1240248616Smm * TODO: study a behavior of ditto utility and improve 1241248616Smm * the condition to fall back into no HFS+ compression. */ 1242248616Smm bk = HFS_BLOCKS(a->compressed_rsrc_position); 1243248616Smm bk += bk >> 7; 1244248616Smm if (bk > HFS_BLOCKS(a->filesize)) 1245248616Smm return hfs_decompress(a); 1246248616Smm /* 1247248616Smm * Write the resourcefork header. 1248248616Smm */ 1249248616Smm if (ret == ARCHIVE_OK) 1250248616Smm ret = hfs_write_resource_fork_header(a); 1251248616Smm /* 1252248616Smm * Finish HFS+ Compression. 1253248616Smm * - Write the decmpfs xattr. 1254248616Smm * - Set the UF_COMPRESSED file flag. 1255248616Smm */ 1256248616Smm if (ret == ARCHIVE_OK) 1257248616Smm ret = hfs_write_decmpfs(a); 1258248616Smm if (ret == ARCHIVE_OK) 1259248616Smm ret = hfs_set_compressed_fflag(a); 1260248616Smm } 1261248616Smm return (ret); 1262248616Smm} 1263248616Smm 1264228753Smmstatic ssize_t 1265248616Smmhfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff, 1266248616Smm size_t size) 1267248616Smm{ 1268248616Smm const char *buffer_to_write; 1269248616Smm size_t bytes_to_write; 1270248616Smm int ret; 1271248616Smm 1272248616Smm if (a->decmpfs_block_count == (unsigned)-1) { 1273248616Smm void *new_block; 1274248616Smm size_t new_size; 1275248616Smm unsigned int block_count; 1276248616Smm 1277248616Smm if (a->decmpfs_header_p == NULL) { 1278248616Smm new_block = malloc(MAX_DECMPFS_XATTR_SIZE 1279248616Smm + sizeof(uint32_t)); 1280248616Smm if (new_block == NULL) { 1281248616Smm archive_set_error(&a->archive, ENOMEM, 1282248616Smm "Can't allocate memory for decmpfs"); 1283248616Smm return (ARCHIVE_FATAL); 1284248616Smm } 1285248616Smm a->decmpfs_header_p = new_block; 1286248616Smm } 1287248616Smm a->decmpfs_attr_size = DECMPFS_HEADER_SIZE; 1288248616Smm archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC], 1289248616Smm DECMPFS_MAGIC); 1290248616Smm archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], 1291248616Smm CMP_RESOURCE_FORK); 1292248616Smm archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE], 1293248616Smm a->filesize); 1294248616Smm 1295248616Smm /* Calculate a block count of the file. */ 1296248616Smm block_count = 1297248616Smm (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) / 1298248616Smm MAX_DECMPFS_BLOCK_SIZE; 1299248616Smm /* 1300248616Smm * Allocate buffer for resource fork. 1301248616Smm * Set up related pointers; 1302248616Smm */ 1303248616Smm new_size = 1304248616Smm RSRC_H_SIZE + /* header */ 1305248616Smm 4 + /* Block count */ 1306248616Smm (block_count * sizeof(uint32_t) * 2) + 1307248616Smm RSRC_F_SIZE; /* footer */ 1308248616Smm if (new_size > a->resource_fork_allocated_size) { 1309248616Smm new_block = realloc(a->resource_fork, new_size); 1310248616Smm if (new_block == NULL) { 1311248616Smm archive_set_error(&a->archive, ENOMEM, 1312248616Smm "Can't allocate memory for ResourceFork"); 1313248616Smm return (ARCHIVE_FATAL); 1314248616Smm } 1315248616Smm a->resource_fork_allocated_size = new_size; 1316248616Smm a->resource_fork = new_block; 1317248616Smm } 1318248616Smm 1319248616Smm /* Allocate uncompressed buffer */ 1320248616Smm if (a->uncompressed_buffer == NULL) { 1321248616Smm new_block = malloc(MAX_DECMPFS_BLOCK_SIZE); 1322248616Smm if (new_block == NULL) { 1323248616Smm archive_set_error(&a->archive, ENOMEM, 1324248616Smm "Can't allocate memory for decmpfs"); 1325248616Smm return (ARCHIVE_FATAL); 1326248616Smm } 1327248616Smm a->uncompressed_buffer = new_block; 1328248616Smm } 1329248616Smm a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; 1330248616Smm a->file_remaining_bytes = a->filesize; 1331248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size; 1332248616Smm 1333248616Smm /* 1334248616Smm * Set up a resource fork. 1335248616Smm */ 1336248616Smm a->rsrc_xattr_options = XATTR_CREATE; 1337248616Smm /* Get the position where we are going to set a bunch 1338248616Smm * of block info. */ 1339248616Smm a->decmpfs_block_info = 1340248616Smm (uint32_t *)(a->resource_fork + RSRC_H_SIZE); 1341248616Smm /* Set the block count to the resource fork. */ 1342248616Smm archive_le32enc(a->decmpfs_block_info++, block_count); 1343248616Smm /* Get the position where we are goint to set compressed 1344248616Smm * data. */ 1345248616Smm a->compressed_rsrc_position = 1346248616Smm RSRC_H_SIZE + 4 + (block_count * 8); 1347248616Smm a->compressed_rsrc_position_v = a->compressed_rsrc_position; 1348248616Smm a->decmpfs_block_count = block_count; 1349248616Smm } 1350248616Smm 1351248616Smm /* Ignore redundant bytes. */ 1352248616Smm if (a->file_remaining_bytes == 0) 1353248616Smm return ((ssize_t)size); 1354248616Smm 1355248616Smm /* Do not overrun a block size. */ 1356248616Smm if (size > a->block_remaining_bytes) 1357248616Smm bytes_to_write = a->block_remaining_bytes; 1358248616Smm else 1359248616Smm bytes_to_write = size; 1360248616Smm /* Do not overrun the file size. */ 1361248616Smm if (bytes_to_write > a->file_remaining_bytes) 1362248616Smm bytes_to_write = a->file_remaining_bytes; 1363248616Smm 1364248616Smm /* For efficiency, if a copy length is full of the uncompressed 1365248616Smm * buffer size, do not copy writing data to it. */ 1366248616Smm if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE) 1367248616Smm buffer_to_write = buff; 1368248616Smm else { 1369248616Smm memcpy(a->uncompressed_buffer + 1370248616Smm MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes, 1371248616Smm buff, bytes_to_write); 1372248616Smm buffer_to_write = a->uncompressed_buffer; 1373248616Smm } 1374248616Smm a->block_remaining_bytes -= bytes_to_write; 1375248616Smm a->file_remaining_bytes -= bytes_to_write; 1376248616Smm 1377248616Smm if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) { 1378248616Smm ret = hfs_drive_compressor(a, buffer_to_write, 1379248616Smm MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes); 1380248616Smm if (ret < 0) 1381248616Smm return (ret); 1382248616Smm a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; 1383248616Smm } 1384248616Smm /* Ignore redundant bytes. */ 1385248616Smm if (a->file_remaining_bytes == 0) 1386248616Smm return ((ssize_t)size); 1387248616Smm return (bytes_to_write); 1388248616Smm} 1389248616Smm 1390248616Smmstatic ssize_t 1391248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff, 1392248616Smm size_t size) 1393248616Smm{ 1394248616Smm uint64_t start_size = size; 1395248616Smm ssize_t bytes_written = 0; 1396248616Smm ssize_t bytes_to_write; 1397248616Smm 1398248616Smm if (size == 0) 1399248616Smm return (ARCHIVE_OK); 1400248616Smm 1401248616Smm if (a->filesize == 0 || a->fd < 0) { 1402248616Smm archive_set_error(&a->archive, 0, 1403248616Smm "Attempt to write to an empty file"); 1404248616Smm return (ARCHIVE_WARN); 1405248616Smm } 1406248616Smm 1407248616Smm /* If this write would run beyond the file size, truncate it. */ 1408248616Smm if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) 1409248616Smm start_size = size = (size_t)(a->filesize - a->offset); 1410248616Smm 1411248616Smm /* Write the data. */ 1412248616Smm while (size > 0) { 1413248616Smm bytes_to_write = size; 1414248616Smm /* Seek if necessary to the specified offset. */ 1415248616Smm if (a->offset < a->fd_offset) { 1416248616Smm /* Can't support backword move. */ 1417248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1418248616Smm "Seek failed"); 1419248616Smm return (ARCHIVE_FATAL); 1420248616Smm } else if (a->offset > a->fd_offset) { 1421248616Smm int64_t skip = a->offset - a->fd_offset; 1422248616Smm char nullblock[1024]; 1423248616Smm 1424248616Smm memset(nullblock, 0, sizeof(nullblock)); 1425248616Smm while (skip > 0) { 1426248616Smm if (skip > (int64_t)sizeof(nullblock)) 1427248616Smm bytes_written = hfs_write_decmpfs_block( 1428248616Smm a, nullblock, sizeof(nullblock)); 1429248616Smm else 1430248616Smm bytes_written = hfs_write_decmpfs_block( 1431248616Smm a, nullblock, skip); 1432248616Smm if (bytes_written < 0) { 1433248616Smm archive_set_error(&a->archive, errno, 1434248616Smm "Write failed"); 1435248616Smm return (ARCHIVE_WARN); 1436248616Smm } 1437248616Smm skip -= bytes_written; 1438248616Smm } 1439248616Smm 1440248616Smm a->fd_offset = a->offset; 1441248616Smm } 1442248616Smm bytes_written = 1443248616Smm hfs_write_decmpfs_block(a, buff, bytes_to_write); 1444248616Smm if (bytes_written < 0) 1445248616Smm return (bytes_written); 1446248616Smm buff += bytes_written; 1447248616Smm size -= bytes_written; 1448248616Smm a->total_bytes_written += bytes_written; 1449248616Smm a->offset += bytes_written; 1450248616Smm a->fd_offset = a->offset; 1451248616Smm } 1452248616Smm return (start_size - size); 1453248616Smm} 1454248616Smm#else 1455248616Smmstatic ssize_t 1456248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff, 1457248616Smm size_t size) 1458248616Smm{ 1459248616Smm return (write_data_block(a, buff, size)); 1460248616Smm} 1461248616Smm#endif 1462248616Smm 1463248616Smmstatic ssize_t 1464231200Smm_archive_write_disk_data_block(struct archive *_a, 1465231200Smm const void *buff, size_t size, int64_t offset) 1466228753Smm{ 1467228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1468228753Smm ssize_t r; 1469228753Smm 1470231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1471231200Smm ARCHIVE_STATE_DATA, "archive_write_data_block"); 1472228753Smm 1473228753Smm a->offset = offset; 1474248616Smm if (a->todo & TODO_HFS_COMPRESSION) 1475248616Smm r = hfs_write_data_block(a, buff, size); 1476248616Smm else 1477248616Smm r = write_data_block(a, buff, size); 1478228753Smm if (r < ARCHIVE_OK) 1479228753Smm return (r); 1480228753Smm if ((size_t)r < size) { 1481228753Smm archive_set_error(&a->archive, 0, 1482228753Smm "Write request too large"); 1483228753Smm return (ARCHIVE_WARN); 1484228753Smm } 1485228753Smm return (ARCHIVE_OK); 1486228753Smm} 1487228753Smm 1488228753Smmstatic ssize_t 1489231200Smm_archive_write_disk_data(struct archive *_a, const void *buff, size_t size) 1490228753Smm{ 1491228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1492228753Smm 1493231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1494228753Smm ARCHIVE_STATE_DATA, "archive_write_data"); 1495228753Smm 1496248616Smm if (a->todo & TODO_HFS_COMPRESSION) 1497248616Smm return (hfs_write_data_block(a, buff, size)); 1498228753Smm return (write_data_block(a, buff, size)); 1499228753Smm} 1500228753Smm 1501228753Smmstatic int 1502231200Smm_archive_write_disk_finish_entry(struct archive *_a) 1503228753Smm{ 1504228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1505228753Smm int ret = ARCHIVE_OK; 1506228753Smm 1507231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1508228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1509228753Smm "archive_write_finish_entry"); 1510228753Smm if (a->archive.state & ARCHIVE_STATE_HEADER) 1511228753Smm return (ARCHIVE_OK); 1512228753Smm archive_clear_error(&a->archive); 1513228753Smm 1514228753Smm /* Pad or truncate file to the right size. */ 1515228753Smm if (a->fd < 0) { 1516228753Smm /* There's no file. */ 1517228753Smm } else if (a->filesize < 0) { 1518228753Smm /* File size is unknown, so we can't set the size. */ 1519228753Smm } else if (a->fd_offset == a->filesize) { 1520228753Smm /* Last write ended at exactly the filesize; we're done. */ 1521228753Smm /* Hopefully, this is the common case. */ 1522248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) 1523248616Smm } else if (a->todo & TODO_HFS_COMPRESSION) { 1524248616Smm char null_d[1024]; 1525248616Smm ssize_t r; 1526248616Smm 1527248616Smm if (a->file_remaining_bytes) 1528248616Smm memset(null_d, 0, sizeof(null_d)); 1529248616Smm while (a->file_remaining_bytes) { 1530248616Smm if (a->file_remaining_bytes > sizeof(null_d)) 1531248616Smm r = hfs_write_data_block( 1532248616Smm a, null_d, sizeof(null_d)); 1533248616Smm else 1534248616Smm r = hfs_write_data_block( 1535248616Smm a, null_d, a->file_remaining_bytes); 1536248616Smm if (r < 0) 1537248616Smm return ((int)r); 1538248616Smm } 1539248616Smm#endif 1540228753Smm } else { 1541228753Smm#if HAVE_FTRUNCATE 1542228753Smm if (ftruncate(a->fd, a->filesize) == -1 && 1543228753Smm a->filesize == 0) { 1544228753Smm archive_set_error(&a->archive, errno, 1545228753Smm "File size could not be restored"); 1546228753Smm return (ARCHIVE_FAILED); 1547228753Smm } 1548228753Smm#endif 1549228753Smm /* 1550228753Smm * Not all platforms implement the XSI option to 1551228753Smm * extend files via ftruncate. Stat() the file again 1552228753Smm * to see what happened. 1553228753Smm */ 1554228753Smm a->pst = NULL; 1555231200Smm if ((ret = lazy_stat(a)) != ARCHIVE_OK) 1556228753Smm return (ret); 1557228753Smm /* We can use lseek()/write() to extend the file if 1558228753Smm * ftruncate didn't work or isn't available. */ 1559228753Smm if (a->st.st_size < a->filesize) { 1560228753Smm const char nul = '\0'; 1561228753Smm if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) { 1562228753Smm archive_set_error(&a->archive, errno, 1563228753Smm "Seek failed"); 1564228753Smm return (ARCHIVE_FATAL); 1565228753Smm } 1566228753Smm if (write(a->fd, &nul, 1) < 0) { 1567228753Smm archive_set_error(&a->archive, errno, 1568228753Smm "Write to restore size failed"); 1569228753Smm return (ARCHIVE_FATAL); 1570228753Smm } 1571228753Smm a->pst = NULL; 1572228753Smm } 1573228753Smm } 1574228753Smm 1575228753Smm /* Restore metadata. */ 1576228753Smm 1577228753Smm /* 1578248616Smm * This is specific to Mac OS X. 1579248616Smm * If the current file is an AppleDouble file, it should be 1580248616Smm * linked with the data fork file and remove it. 1581248616Smm */ 1582248616Smm if (a->todo & TODO_APPLEDOUBLE) { 1583248616Smm int r2 = fixup_appledouble(a, a->name); 1584248616Smm if (r2 == ARCHIVE_EOF) { 1585248616Smm /* The current file has been successfully linked 1586248616Smm * with the data fork file and removed. So there 1587248616Smm * is nothing to do on the current file. */ 1588248616Smm goto finish_metadata; 1589248616Smm } 1590248616Smm if (r2 < ret) ret = r2; 1591248616Smm } 1592248616Smm 1593248616Smm /* 1594228753Smm * Look up the "real" UID only if we're going to need it. 1595228753Smm * TODO: the TODO_SGID condition can be dropped here, can't it? 1596228753Smm */ 1597228753Smm if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { 1598231200Smm a->uid = archive_write_disk_uid(&a->archive, 1599228753Smm archive_entry_uname(a->entry), 1600228753Smm archive_entry_uid(a->entry)); 1601228753Smm } 1602228753Smm /* Look up the "real" GID only if we're going to need it. */ 1603228753Smm /* TODO: the TODO_SUID condition can be dropped here, can't it? */ 1604228753Smm if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { 1605231200Smm a->gid = archive_write_disk_gid(&a->archive, 1606228753Smm archive_entry_gname(a->entry), 1607228753Smm archive_entry_gid(a->entry)); 1608228753Smm } 1609231200Smm 1610228753Smm /* 1611231200Smm * Restore ownership before set_mode tries to restore suid/sgid 1612228753Smm * bits. If we set the owner, we know what it is and can skip 1613228753Smm * a stat() call to examine the ownership of the file on disk. 1614228753Smm */ 1615248616Smm if (a->todo & TODO_OWNER) { 1616248616Smm int r2 = set_ownership(a); 1617248616Smm if (r2 < ret) ret = r2; 1618248616Smm } 1619231200Smm 1620231200Smm /* 1621231200Smm * set_mode must precede ACLs on systems such as Solaris and 1622231200Smm * FreeBSD where setting the mode implicitly clears extended ACLs 1623231200Smm */ 1624228753Smm if (a->todo & TODO_MODE) { 1625228753Smm int r2 = set_mode(a, a->mode); 1626228753Smm if (r2 < ret) ret = r2; 1627228753Smm } 1628228753Smm 1629228753Smm /* 1630228753Smm * Security-related extended attributes (such as 1631228753Smm * security.capability on Linux) have to be restored last, 1632228753Smm * since they're implicitly removed by other file changes. 1633228753Smm */ 1634228753Smm if (a->todo & TODO_XATTR) { 1635228753Smm int r2 = set_xattrs(a); 1636228753Smm if (r2 < ret) ret = r2; 1637228753Smm } 1638228753Smm 1639228753Smm /* 1640228753Smm * Some flags prevent file modification; they must be restored after 1641228753Smm * file contents are written. 1642228753Smm */ 1643228753Smm if (a->todo & TODO_FFLAGS) { 1644228753Smm int r2 = set_fflags(a); 1645228753Smm if (r2 < ret) ret = r2; 1646228753Smm } 1647231200Smm 1648228753Smm /* 1649231200Smm * Time must follow most other metadata; 1650228753Smm * otherwise atime will get changed. 1651228753Smm */ 1652228753Smm if (a->todo & TODO_TIMES) { 1653231200Smm int r2 = set_times_from_entry(a); 1654228753Smm if (r2 < ret) ret = r2; 1655228753Smm } 1656228753Smm 1657231200Smm /* 1658231200Smm * Mac extended metadata includes ACLs. 1659231200Smm */ 1660231200Smm if (a->todo & TODO_MAC_METADATA) { 1661231200Smm const void *metadata; 1662231200Smm size_t metadata_size; 1663231200Smm metadata = archive_entry_mac_metadata(a->entry, &metadata_size); 1664231200Smm if (metadata != NULL && metadata_size > 0) { 1665248616Smm int r2 = set_mac_metadata(a, archive_entry_pathname( 1666248616Smm a->entry), metadata, metadata_size); 1667231200Smm if (r2 < ret) ret = r2; 1668231200Smm } 1669231200Smm } 1670231200Smm 1671231200Smm /* 1672231200Smm * ACLs must be restored after timestamps because there are 1673231200Smm * ACLs that prevent attribute changes (including time). 1674231200Smm */ 1675231200Smm if (a->todo & TODO_ACLS) { 1676238909Smm int r2 = archive_write_disk_set_acls(&a->archive, a->fd, 1677231200Smm archive_entry_pathname(a->entry), 1678231200Smm archive_entry_acl(a->entry)); 1679231200Smm if (r2 < ret) ret = r2; 1680231200Smm } 1681231200Smm 1682248616Smmfinish_metadata: 1683228753Smm /* If there's an fd, we can close it now. */ 1684228753Smm if (a->fd >= 0) { 1685228753Smm close(a->fd); 1686228753Smm a->fd = -1; 1687228753Smm } 1688228753Smm /* If there's an entry, we can release it now. */ 1689228753Smm if (a->entry) { 1690228753Smm archive_entry_free(a->entry); 1691228753Smm a->entry = NULL; 1692228753Smm } 1693228753Smm a->archive.state = ARCHIVE_STATE_HEADER; 1694228753Smm return (ret); 1695228753Smm} 1696228753Smm 1697228753Smmint 1698228753Smmarchive_write_disk_set_group_lookup(struct archive *_a, 1699228753Smm void *private_data, 1700231200Smm int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid), 1701228753Smm void (*cleanup_gid)(void *private)) 1702228753Smm{ 1703228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1704231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1705228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); 1706228753Smm 1707231200Smm if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) 1708231200Smm (a->cleanup_gid)(a->lookup_gid_data); 1709231200Smm 1710228753Smm a->lookup_gid = lookup_gid; 1711228753Smm a->cleanup_gid = cleanup_gid; 1712228753Smm a->lookup_gid_data = private_data; 1713228753Smm return (ARCHIVE_OK); 1714228753Smm} 1715228753Smm 1716228753Smmint 1717228753Smmarchive_write_disk_set_user_lookup(struct archive *_a, 1718228753Smm void *private_data, 1719231200Smm int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid), 1720228753Smm void (*cleanup_uid)(void *private)) 1721228753Smm{ 1722228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1723231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1724228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); 1725228753Smm 1726231200Smm if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) 1727231200Smm (a->cleanup_uid)(a->lookup_uid_data); 1728231200Smm 1729228753Smm a->lookup_uid = lookup_uid; 1730228753Smm a->cleanup_uid = cleanup_uid; 1731228753Smm a->lookup_uid_data = private_data; 1732228753Smm return (ARCHIVE_OK); 1733228753Smm} 1734228753Smm 1735231200Smmint64_t 1736231200Smmarchive_write_disk_gid(struct archive *_a, const char *name, int64_t id) 1737231200Smm{ 1738231200Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1739231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1740231200Smm ARCHIVE_STATE_ANY, "archive_write_disk_gid"); 1741231200Smm if (a->lookup_gid) 1742231200Smm return (a->lookup_gid)(a->lookup_gid_data, name, id); 1743231200Smm return (id); 1744231200Smm} 1745231200Smm 1746231200Smmint64_t 1747231200Smmarchive_write_disk_uid(struct archive *_a, const char *name, int64_t id) 1748231200Smm{ 1749238909Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1750238909Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1751238909Smm ARCHIVE_STATE_ANY, "archive_write_disk_uid"); 1752238909Smm if (a->lookup_uid) 1753238909Smm return (a->lookup_uid)(a->lookup_uid_data, name, id); 1754238909Smm return (id); 1755231200Smm} 1756228753Smm 1757228753Smm/* 1758228753Smm * Create a new archive_write_disk object and initialize it with global state. 1759228753Smm */ 1760228753Smmstruct archive * 1761228753Smmarchive_write_disk_new(void) 1762228753Smm{ 1763228753Smm struct archive_write_disk *a; 1764228753Smm 1765228753Smm a = (struct archive_write_disk *)malloc(sizeof(*a)); 1766228753Smm if (a == NULL) 1767228753Smm return (NULL); 1768228753Smm memset(a, 0, sizeof(*a)); 1769228753Smm a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; 1770228753Smm /* We're ready to write a header immediately. */ 1771228753Smm a->archive.state = ARCHIVE_STATE_HEADER; 1772228753Smm a->archive.vtable = archive_write_disk_vtable(); 1773228753Smm a->start_time = time(NULL); 1774231200Smm /* Query and restore the umask. */ 1775231200Smm umask(a->user_umask = umask(0)); 1776228753Smm#ifdef HAVE_GETEUID 1777228753Smm a->user_uid = geteuid(); 1778228753Smm#endif /* HAVE_GETEUID */ 1779228753Smm if (archive_string_ensure(&a->path_safe, 512) == NULL) { 1780228753Smm free(a); 1781228753Smm return (NULL); 1782228753Smm } 1783248616Smm#ifdef HAVE_ZLIB_H 1784248616Smm a->decmpfs_compression_level = 5; 1785248616Smm#endif 1786228753Smm return (&a->archive); 1787228753Smm} 1788228753Smm 1789228753Smm 1790228753Smm/* 1791228753Smm * If pathname is longer than PATH_MAX, chdir to a suitable 1792228753Smm * intermediate dir and edit the path down to a shorter suffix. Note 1793228753Smm * that this routine never returns an error; if the chdir() attempt 1794228753Smm * fails for any reason, we just go ahead with the long pathname. The 1795228753Smm * object creation is likely to fail, but any error will get handled 1796228753Smm * at that time. 1797228753Smm */ 1798231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX) 1799228753Smmstatic void 1800228753Smmedit_deep_directories(struct archive_write_disk *a) 1801228753Smm{ 1802228753Smm int ret; 1803228753Smm char *tail = a->name; 1804228753Smm 1805228753Smm /* If path is short, avoid the open() below. */ 1806306941Sdelphij if (strlen(tail) < PATH_MAX) 1807228753Smm return; 1808228753Smm 1809228753Smm /* Try to record our starting dir. */ 1810248616Smm a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC); 1811248616Smm __archive_ensure_cloexec_flag(a->restore_pwd); 1812228753Smm if (a->restore_pwd < 0) 1813228753Smm return; 1814228753Smm 1815228753Smm /* As long as the path is too long... */ 1816306941Sdelphij while (strlen(tail) >= PATH_MAX) { 1817228753Smm /* Locate a dir prefix shorter than PATH_MAX. */ 1818228753Smm tail += PATH_MAX - 8; 1819228753Smm while (tail > a->name && *tail != '/') 1820228753Smm tail--; 1821228753Smm /* Exit if we find a too-long path component. */ 1822228753Smm if (tail <= a->name) 1823228753Smm return; 1824228753Smm /* Create the intermediate dir and chdir to it. */ 1825228753Smm *tail = '\0'; /* Terminate dir portion */ 1826228753Smm ret = create_dir(a, a->name); 1827228753Smm if (ret == ARCHIVE_OK && chdir(a->name) != 0) 1828228753Smm ret = ARCHIVE_FAILED; 1829228753Smm *tail = '/'; /* Restore the / we removed. */ 1830228753Smm if (ret != ARCHIVE_OK) 1831228753Smm return; 1832228753Smm tail++; 1833228753Smm /* The chdir() succeeded; we've now shortened the path. */ 1834228753Smm a->name = tail; 1835228753Smm } 1836228753Smm return; 1837228753Smm} 1838228753Smm#endif 1839228753Smm 1840228753Smm/* 1841228753Smm * The main restore function. 1842228753Smm */ 1843228753Smmstatic int 1844228753Smmrestore_entry(struct archive_write_disk *a) 1845228753Smm{ 1846228753Smm int ret = ARCHIVE_OK, en; 1847228753Smm 1848228753Smm if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { 1849228753Smm /* 1850228753Smm * TODO: Fix this. Apparently, there are platforms 1851228753Smm * that still allow root to hose the entire filesystem 1852228753Smm * by unlinking a dir. The S_ISDIR() test above 1853228753Smm * prevents us from using unlink() here if the new 1854228753Smm * object is a dir, but that doesn't mean the old 1855228753Smm * object isn't a dir. 1856228753Smm */ 1857228753Smm if (unlink(a->name) == 0) { 1858228753Smm /* We removed it, reset cached stat. */ 1859228753Smm a->pst = NULL; 1860228753Smm } else if (errno == ENOENT) { 1861228753Smm /* File didn't exist, that's just as good. */ 1862228753Smm } else if (rmdir(a->name) == 0) { 1863228753Smm /* It was a dir, but now it's gone. */ 1864228753Smm a->pst = NULL; 1865228753Smm } else { 1866228753Smm /* We tried, but couldn't get rid of it. */ 1867228753Smm archive_set_error(&a->archive, errno, 1868228753Smm "Could not unlink"); 1869228753Smm return(ARCHIVE_FAILED); 1870228753Smm } 1871228753Smm } 1872228753Smm 1873228753Smm /* Try creating it first; if this fails, we'll try to recover. */ 1874228753Smm en = create_filesystem_object(a); 1875228753Smm 1876228753Smm if ((en == ENOTDIR || en == ENOENT) 1877228753Smm && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) { 1878228753Smm /* If the parent dir doesn't exist, try creating it. */ 1879228753Smm create_parent_dir(a, a->name); 1880228753Smm /* Now try to create the object again. */ 1881228753Smm en = create_filesystem_object(a); 1882228753Smm } 1883228753Smm 1884228753Smm if ((en == EISDIR || en == EEXIST) 1885228753Smm && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { 1886228753Smm /* If we're not overwriting, we're done. */ 1887231200Smm archive_entry_unset_size(a->entry); 1888231200Smm return (ARCHIVE_OK); 1889228753Smm } 1890228753Smm 1891228753Smm /* 1892228753Smm * Some platforms return EISDIR if you call 1893228753Smm * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some 1894228753Smm * return EEXIST. POSIX is ambiguous, requiring EISDIR 1895228753Smm * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT) 1896228753Smm * on an existing item. 1897228753Smm */ 1898228753Smm if (en == EISDIR) { 1899228753Smm /* A dir is in the way of a non-dir, rmdir it. */ 1900228753Smm if (rmdir(a->name) != 0) { 1901228753Smm archive_set_error(&a->archive, errno, 1902228753Smm "Can't remove already-existing dir"); 1903228753Smm return (ARCHIVE_FAILED); 1904228753Smm } 1905228753Smm a->pst = NULL; 1906228753Smm /* Try again. */ 1907228753Smm en = create_filesystem_object(a); 1908228753Smm } else if (en == EEXIST) { 1909228753Smm /* 1910228753Smm * We know something is in the way, but we don't know what; 1911228753Smm * we need to find out before we go any further. 1912228753Smm */ 1913228753Smm int r = 0; 1914228753Smm /* 1915231200Smm * The SECURE_SYMLINKS logic has already removed a 1916228753Smm * symlink to a dir if the client wants that. So 1917228753Smm * follow the symlink if we're creating a dir. 1918228753Smm */ 1919228753Smm if (S_ISDIR(a->mode)) 1920228753Smm r = stat(a->name, &a->st); 1921228753Smm /* 1922228753Smm * If it's not a dir (or it's a broken symlink), 1923228753Smm * then don't follow it. 1924228753Smm */ 1925228753Smm if (r != 0 || !S_ISDIR(a->mode)) 1926228753Smm r = lstat(a->name, &a->st); 1927228753Smm if (r != 0) { 1928228753Smm archive_set_error(&a->archive, errno, 1929228753Smm "Can't stat existing object"); 1930228753Smm return (ARCHIVE_FAILED); 1931228753Smm } 1932228753Smm 1933228753Smm /* 1934228753Smm * NO_OVERWRITE_NEWER doesn't apply to directories. 1935228753Smm */ 1936228753Smm if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) 1937228753Smm && !S_ISDIR(a->st.st_mode)) { 1938228753Smm if (!older(&(a->st), a->entry)) { 1939231200Smm archive_entry_unset_size(a->entry); 1940231200Smm return (ARCHIVE_OK); 1941228753Smm } 1942228753Smm } 1943228753Smm 1944228753Smm /* If it's our archive, we're done. */ 1945231200Smm if (a->skip_file_set && 1946238856Smm a->st.st_dev == (dev_t)a->skip_file_dev && 1947238856Smm a->st.st_ino == (ino_t)a->skip_file_ino) { 1948238856Smm archive_set_error(&a->archive, 0, 1949238856Smm "Refusing to overwrite archive"); 1950228753Smm return (ARCHIVE_FAILED); 1951228753Smm } 1952228753Smm 1953228753Smm if (!S_ISDIR(a->st.st_mode)) { 1954228753Smm /* A non-dir is in the way, unlink it. */ 1955228753Smm if (unlink(a->name) != 0) { 1956228753Smm archive_set_error(&a->archive, errno, 1957228753Smm "Can't unlink already-existing object"); 1958228753Smm return (ARCHIVE_FAILED); 1959228753Smm } 1960228753Smm a->pst = NULL; 1961228753Smm /* Try again. */ 1962228753Smm en = create_filesystem_object(a); 1963228753Smm } else if (!S_ISDIR(a->mode)) { 1964228753Smm /* A dir is in the way of a non-dir, rmdir it. */ 1965228753Smm if (rmdir(a->name) != 0) { 1966228753Smm archive_set_error(&a->archive, errno, 1967238856Smm "Can't replace existing directory with non-directory"); 1968228753Smm return (ARCHIVE_FAILED); 1969228753Smm } 1970228753Smm /* Try again. */ 1971228753Smm en = create_filesystem_object(a); 1972228753Smm } else { 1973228753Smm /* 1974228753Smm * There's a dir in the way of a dir. Don't 1975228753Smm * waste time with rmdir()/mkdir(), just fix 1976228753Smm * up the permissions on the existing dir. 1977228753Smm * Note that we don't change perms on existing 1978228753Smm * dirs unless _EXTRACT_PERM is specified. 1979228753Smm */ 1980228753Smm if ((a->mode != a->st.st_mode) 1981228753Smm && (a->todo & TODO_MODE_FORCE)) 1982228753Smm a->deferred |= (a->todo & TODO_MODE); 1983228753Smm /* Ownership doesn't need deferred fixup. */ 1984228753Smm en = 0; /* Forget the EEXIST. */ 1985228753Smm } 1986228753Smm } 1987228753Smm 1988228753Smm if (en) { 1989228753Smm /* Everything failed; give up here. */ 1990228753Smm archive_set_error(&a->archive, en, "Can't create '%s'", 1991228753Smm a->name); 1992228753Smm return (ARCHIVE_FAILED); 1993228753Smm } 1994228753Smm 1995228753Smm a->pst = NULL; /* Cached stat data no longer valid. */ 1996228753Smm return (ret); 1997228753Smm} 1998228753Smm 1999228753Smm/* 2000228753Smm * Returns 0 if creation succeeds, or else returns errno value from 2001228753Smm * the failed system call. Note: This function should only ever perform 2002228753Smm * a single system call. 2003228753Smm */ 2004228753Smmstatic int 2005228753Smmcreate_filesystem_object(struct archive_write_disk *a) 2006228753Smm{ 2007228753Smm /* Create the entry. */ 2008228753Smm const char *linkname; 2009228753Smm mode_t final_mode, mode; 2010228753Smm int r; 2011306941Sdelphij /* these for check_symlinks_fsobj */ 2012306941Sdelphij char *linkname_copy; /* non-const copy of linkname */ 2013306941Sdelphij struct archive_string error_string; 2014306941Sdelphij int error_number; 2015228753Smm 2016228753Smm /* We identify hard/symlinks according to the link names. */ 2017228753Smm /* Since link(2) and symlink(2) don't handle modes, we're done here. */ 2018228753Smm linkname = archive_entry_hardlink(a->entry); 2019228753Smm if (linkname != NULL) { 2020228753Smm#if !HAVE_LINK 2021228753Smm return (EPERM); 2022228753Smm#else 2023306941Sdelphij archive_string_init(&error_string); 2024306941Sdelphij linkname_copy = strdup(linkname); 2025306941Sdelphij if (linkname_copy == NULL) { 2026306941Sdelphij return (EPERM); 2027306941Sdelphij } 2028306941Sdelphij /* TODO: consider using the cleaned-up path as the link target? */ 2029306941Sdelphij r = cleanup_pathname_fsobj(linkname_copy, &error_number, &error_string, a->flags); 2030306941Sdelphij if (r != ARCHIVE_OK) { 2031306941Sdelphij archive_set_error(&a->archive, error_number, "%s", error_string.s); 2032306941Sdelphij free(linkname_copy); 2033306941Sdelphij /* EPERM is more appropriate than error_number for our callers */ 2034306941Sdelphij return (EPERM); 2035306941Sdelphij } 2036306941Sdelphij r = check_symlinks_fsobj(linkname_copy, &error_number, &error_string, a->flags); 2037306941Sdelphij if (r != ARCHIVE_OK) { 2038306941Sdelphij archive_set_error(&a->archive, error_number, "%s", error_string.s); 2039306941Sdelphij free(linkname_copy); 2040306941Sdelphij /* EPERM is more appropriate than error_number for our callers */ 2041306941Sdelphij return (EPERM); 2042306941Sdelphij } 2043306941Sdelphij free(linkname_copy); 2044228753Smm r = link(linkname, a->name) ? errno : 0; 2045228753Smm /* 2046228753Smm * New cpio and pax formats allow hardlink entries 2047228753Smm * to carry data, so we may have to open the file 2048228753Smm * for hardlink entries. 2049228753Smm * 2050228753Smm * If the hardlink was successfully created and 2051228753Smm * the archive doesn't have carry data for it, 2052231200Smm * consider it to be non-authoritative for meta data. 2053228753Smm * This is consistent with GNU tar and BSD pax. 2054228753Smm * If the hardlink does carry data, let the last 2055228753Smm * archive entry decide ownership. 2056228753Smm */ 2057228753Smm if (r == 0 && a->filesize <= 0) { 2058228753Smm a->todo = 0; 2059228753Smm a->deferred = 0; 2060231200Smm } else if (r == 0 && a->filesize > 0) { 2061248616Smm a->fd = open(a->name, 2062306941Sdelphij O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC | O_NOFOLLOW); 2063248616Smm __archive_ensure_cloexec_flag(a->fd); 2064228753Smm if (a->fd < 0) 2065228753Smm r = errno; 2066228753Smm } 2067228753Smm return (r); 2068228753Smm#endif 2069228753Smm } 2070228753Smm linkname = archive_entry_symlink(a->entry); 2071228753Smm if (linkname != NULL) { 2072228753Smm#if HAVE_SYMLINK 2073228753Smm return symlink(linkname, a->name) ? errno : 0; 2074228753Smm#else 2075228753Smm return (EPERM); 2076228753Smm#endif 2077228753Smm } 2078228753Smm 2079228753Smm /* 2080228753Smm * The remaining system calls all set permissions, so let's 2081228753Smm * try to take advantage of that to avoid an extra chmod() 2082228753Smm * call. (Recall that umask is set to zero right now!) 2083228753Smm */ 2084228753Smm 2085228753Smm /* Mode we want for the final restored object (w/o file type bits). */ 2086228753Smm final_mode = a->mode & 07777; 2087228753Smm /* 2088228753Smm * The mode that will actually be restored in this step. Note 2089228753Smm * that SUID, SGID, etc, require additional work to ensure 2090228753Smm * security, so we never restore them at this point. 2091228753Smm */ 2092248616Smm mode = final_mode & 0777 & ~a->user_umask; 2093228753Smm 2094228753Smm switch (a->mode & AE_IFMT) { 2095228753Smm default: 2096228753Smm /* POSIX requires that we fall through here. */ 2097228753Smm /* FALLTHROUGH */ 2098228753Smm case AE_IFREG: 2099228753Smm a->fd = open(a->name, 2100248616Smm O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode); 2101248616Smm __archive_ensure_cloexec_flag(a->fd); 2102228753Smm r = (a->fd < 0); 2103228753Smm break; 2104228753Smm case AE_IFCHR: 2105228753Smm#ifdef HAVE_MKNOD 2106228753Smm /* Note: we use AE_IFCHR for the case label, and 2107228753Smm * S_IFCHR for the mknod() call. This is correct. */ 2108228753Smm r = mknod(a->name, mode | S_IFCHR, 2109228753Smm archive_entry_rdev(a->entry)); 2110228753Smm break; 2111228753Smm#else 2112228753Smm /* TODO: Find a better way to warn about our inability 2113228753Smm * to restore a char device node. */ 2114228753Smm return (EINVAL); 2115228753Smm#endif /* HAVE_MKNOD */ 2116228753Smm case AE_IFBLK: 2117228753Smm#ifdef HAVE_MKNOD 2118228753Smm r = mknod(a->name, mode | S_IFBLK, 2119228753Smm archive_entry_rdev(a->entry)); 2120228753Smm break; 2121228753Smm#else 2122228753Smm /* TODO: Find a better way to warn about our inability 2123228753Smm * to restore a block device node. */ 2124228753Smm return (EINVAL); 2125228753Smm#endif /* HAVE_MKNOD */ 2126228753Smm case AE_IFDIR: 2127228753Smm mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; 2128228753Smm r = mkdir(a->name, mode); 2129228753Smm if (r == 0) { 2130228753Smm /* Defer setting dir times. */ 2131228753Smm a->deferred |= (a->todo & TODO_TIMES); 2132228753Smm a->todo &= ~TODO_TIMES; 2133228753Smm /* Never use an immediate chmod(). */ 2134228753Smm /* We can't avoid the chmod() entirely if EXTRACT_PERM 2135228753Smm * because of SysV SGID inheritance. */ 2136228753Smm if ((mode != final_mode) 2137228753Smm || (a->flags & ARCHIVE_EXTRACT_PERM)) 2138228753Smm a->deferred |= (a->todo & TODO_MODE); 2139228753Smm a->todo &= ~TODO_MODE; 2140228753Smm } 2141228753Smm break; 2142228753Smm case AE_IFIFO: 2143228753Smm#ifdef HAVE_MKFIFO 2144228753Smm r = mkfifo(a->name, mode); 2145228753Smm break; 2146228753Smm#else 2147228753Smm /* TODO: Find a better way to warn about our inability 2148228753Smm * to restore a fifo. */ 2149228753Smm return (EINVAL); 2150228753Smm#endif /* HAVE_MKFIFO */ 2151228753Smm } 2152228753Smm 2153228753Smm /* All the system calls above set errno on failure. */ 2154228753Smm if (r) 2155228753Smm return (errno); 2156228753Smm 2157228753Smm /* If we managed to set the final mode, we've avoided a chmod(). */ 2158228753Smm if (mode == final_mode) 2159228753Smm a->todo &= ~TODO_MODE; 2160228753Smm return (0); 2161228753Smm} 2162228753Smm 2163228753Smm/* 2164228753Smm * Cleanup function for archive_extract. Mostly, this involves processing 2165228753Smm * the fixup list, which is used to address a number of problems: 2166228753Smm * * Dir permissions might prevent us from restoring a file in that 2167228753Smm * dir, so we restore the dir with minimum 0700 permissions first, 2168228753Smm * then correct the mode at the end. 2169228753Smm * * Similarly, the act of restoring a file touches the directory 2170228753Smm * and changes the timestamp on the dir, so we have to touch-up dir 2171228753Smm * timestamps at the end as well. 2172228753Smm * * Some file flags can interfere with the restore by, for example, 2173228753Smm * preventing the creation of hardlinks to those files. 2174231200Smm * * Mac OS extended metadata includes ACLs, so must be deferred on dirs. 2175228753Smm * 2176228753Smm * Note that tar/cpio do not require that archives be in a particular 2177228753Smm * order; there is no way to know when the last file has been restored 2178228753Smm * within a directory, so there's no way to optimize the memory usage 2179228753Smm * here by fixing up the directory any earlier than the 2180228753Smm * end-of-archive. 2181228753Smm * 2182228753Smm * XXX TODO: Directory ACLs should be restored here, for the same 2183228753Smm * reason we set directory perms here. XXX 2184228753Smm */ 2185228753Smmstatic int 2186231200Smm_archive_write_disk_close(struct archive *_a) 2187228753Smm{ 2188228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 2189228753Smm struct fixup_entry *next, *p; 2190228753Smm int ret; 2191228753Smm 2192231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 2193228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 2194228753Smm "archive_write_disk_close"); 2195231200Smm ret = _archive_write_disk_finish_entry(&a->archive); 2196228753Smm 2197228753Smm /* Sort dir list so directories are fixed up in depth-first order. */ 2198228753Smm p = sort_dir_list(a->fixup_list); 2199228753Smm 2200228753Smm while (p != NULL) { 2201228753Smm a->pst = NULL; /* Mark stat cache as out-of-date. */ 2202228753Smm if (p->fixup & TODO_TIMES) { 2203231200Smm set_times(a, -1, p->mode, p->name, 2204231200Smm p->atime, p->atime_nanos, 2205231200Smm p->birthtime, p->birthtime_nanos, 2206231200Smm p->mtime, p->mtime_nanos, 2207231200Smm p->ctime, p->ctime_nanos); 2208228753Smm } 2209228753Smm if (p->fixup & TODO_MODE_BASE) 2210228753Smm chmod(p->name, p->mode); 2211231200Smm if (p->fixup & TODO_ACLS) 2212238909Smm archive_write_disk_set_acls(&a->archive, 2213238909Smm -1, p->name, &p->acl); 2214228753Smm if (p->fixup & TODO_FFLAGS) 2215228753Smm set_fflags_platform(a, -1, p->name, 2216228753Smm p->mode, p->fflags_set, 0); 2217231200Smm if (p->fixup & TODO_MAC_METADATA) 2218231200Smm set_mac_metadata(a, p->name, p->mac_metadata, 2219231200Smm p->mac_metadata_size); 2220228753Smm next = p->next; 2221231200Smm archive_acl_clear(&p->acl); 2222231200Smm free(p->mac_metadata); 2223228753Smm free(p->name); 2224228753Smm free(p); 2225228753Smm p = next; 2226228753Smm } 2227228753Smm a->fixup_list = NULL; 2228228753Smm return (ret); 2229228753Smm} 2230228753Smm 2231228753Smmstatic int 2232231200Smm_archive_write_disk_free(struct archive *_a) 2233228753Smm{ 2234231200Smm struct archive_write_disk *a; 2235228753Smm int ret; 2236231200Smm if (_a == NULL) 2237231200Smm return (ARCHIVE_OK); 2238231200Smm archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC, 2239231200Smm ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); 2240231200Smm a = (struct archive_write_disk *)_a; 2241231200Smm ret = _archive_write_disk_close(&a->archive); 2242231200Smm archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); 2243231200Smm archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); 2244228753Smm if (a->entry) 2245228753Smm archive_entry_free(a->entry); 2246228753Smm archive_string_free(&a->_name_data); 2247228753Smm archive_string_free(&a->archive.error_string); 2248228753Smm archive_string_free(&a->path_safe); 2249231200Smm a->archive.magic = 0; 2250231200Smm __archive_clean(&a->archive); 2251248616Smm free(a->decmpfs_header_p); 2252248616Smm free(a->resource_fork); 2253248616Smm free(a->compressed_buffer); 2254248616Smm free(a->uncompressed_buffer); 2255248616Smm#ifdef HAVE_ZLIB_H 2256248616Smm if (a->stream_valid) { 2257248616Smm switch (deflateEnd(&a->stream)) { 2258248616Smm case Z_OK: 2259248616Smm break; 2260248616Smm default: 2261248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 2262248616Smm "Failed to clean up compressor"); 2263248616Smm ret = ARCHIVE_FATAL; 2264248616Smm break; 2265248616Smm } 2266248616Smm } 2267248616Smm#endif 2268228753Smm free(a); 2269228753Smm return (ret); 2270228753Smm} 2271228753Smm 2272228753Smm/* 2273228753Smm * Simple O(n log n) merge sort to order the fixup list. In 2274228753Smm * particular, we want to restore dir timestamps depth-first. 2275228753Smm */ 2276228753Smmstatic struct fixup_entry * 2277228753Smmsort_dir_list(struct fixup_entry *p) 2278228753Smm{ 2279228753Smm struct fixup_entry *a, *b, *t; 2280228753Smm 2281228753Smm if (p == NULL) 2282228753Smm return (NULL); 2283228753Smm /* A one-item list is already sorted. */ 2284228753Smm if (p->next == NULL) 2285228753Smm return (p); 2286228753Smm 2287228753Smm /* Step 1: split the list. */ 2288228753Smm t = p; 2289228753Smm a = p->next->next; 2290228753Smm while (a != NULL) { 2291228753Smm /* Step a twice, t once. */ 2292228753Smm a = a->next; 2293228753Smm if (a != NULL) 2294228753Smm a = a->next; 2295228753Smm t = t->next; 2296228753Smm } 2297228753Smm /* Now, t is at the mid-point, so break the list here. */ 2298228753Smm b = t->next; 2299228753Smm t->next = NULL; 2300228753Smm a = p; 2301228753Smm 2302228753Smm /* Step 2: Recursively sort the two sub-lists. */ 2303228753Smm a = sort_dir_list(a); 2304228753Smm b = sort_dir_list(b); 2305228753Smm 2306228753Smm /* Step 3: Merge the returned lists. */ 2307228753Smm /* Pick the first element for the merged list. */ 2308228753Smm if (strcmp(a->name, b->name) > 0) { 2309228753Smm t = p = a; 2310228753Smm a = a->next; 2311228753Smm } else { 2312228753Smm t = p = b; 2313228753Smm b = b->next; 2314228753Smm } 2315228753Smm 2316228753Smm /* Always put the later element on the list first. */ 2317228753Smm while (a != NULL && b != NULL) { 2318228753Smm if (strcmp(a->name, b->name) > 0) { 2319228753Smm t->next = a; 2320228753Smm a = a->next; 2321228753Smm } else { 2322228753Smm t->next = b; 2323228753Smm b = b->next; 2324228753Smm } 2325228753Smm t = t->next; 2326228753Smm } 2327228753Smm 2328228753Smm /* Only one list is non-empty, so just splice it on. */ 2329228753Smm if (a != NULL) 2330228753Smm t->next = a; 2331228753Smm if (b != NULL) 2332228753Smm t->next = b; 2333228753Smm 2334228753Smm return (p); 2335228753Smm} 2336228753Smm 2337228753Smm/* 2338228753Smm * Returns a new, initialized fixup entry. 2339228753Smm * 2340228753Smm * TODO: Reduce the memory requirements for this list by using a tree 2341228753Smm * structure rather than a simple list of names. 2342228753Smm */ 2343228753Smmstatic struct fixup_entry * 2344228753Smmnew_fixup(struct archive_write_disk *a, const char *pathname) 2345228753Smm{ 2346228753Smm struct fixup_entry *fe; 2347228753Smm 2348231200Smm fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry)); 2349248616Smm if (fe == NULL) { 2350248616Smm archive_set_error(&a->archive, ENOMEM, 2351248616Smm "Can't allocate memory for a fixup"); 2352228753Smm return (NULL); 2353248616Smm } 2354228753Smm fe->next = a->fixup_list; 2355228753Smm a->fixup_list = fe; 2356228753Smm fe->fixup = 0; 2357228753Smm fe->name = strdup(pathname); 2358228753Smm return (fe); 2359228753Smm} 2360228753Smm 2361228753Smm/* 2362228753Smm * Returns a fixup structure for the current entry. 2363228753Smm */ 2364228753Smmstatic struct fixup_entry * 2365228753Smmcurrent_fixup(struct archive_write_disk *a, const char *pathname) 2366228753Smm{ 2367228753Smm if (a->current_fixup == NULL) 2368228753Smm a->current_fixup = new_fixup(a, pathname); 2369228753Smm return (a->current_fixup); 2370228753Smm} 2371228753Smm 2372228753Smm/* 2373228753Smm * TODO: Someday, integrate this with the deep dir support; they both 2374228753Smm * scan the path and both can be optimized by comparing against other 2375228753Smm * recent paths. 2376228753Smm */ 2377228753Smm/* TODO: Extend this to support symlinks on Windows Vista and later. */ 2378306941Sdelphij 2379306941Sdelphij/* 2380306941Sdelphij * Checks the given path to see if any elements along it are symlinks. Returns 2381306941Sdelphij * ARCHIVE_OK if there are none, otherwise puts an error in errmsg. 2382306941Sdelphij */ 2383228753Smmstatic int 2384306941Sdelphijcheck_symlinks_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags) 2385228753Smm{ 2386228753Smm#if !defined(HAVE_LSTAT) 2387228753Smm /* Platform doesn't have lstat, so we can't look for symlinks. */ 2388306941Sdelphij (void)path; /* UNUSED */ 2389306941Sdelphij (void)error_number; /* UNUSED */ 2390306941Sdelphij (void)error_string; /* UNUSED */ 2391306941Sdelphij (void)flags; /* UNUSED */ 2392228753Smm return (ARCHIVE_OK); 2393228753Smm#else 2394306941Sdelphij int res = ARCHIVE_OK; 2395306941Sdelphij char *tail; 2396306941Sdelphij char *head; 2397306941Sdelphij int last; 2398228753Smm char c; 2399228753Smm int r; 2400228753Smm struct stat st; 2401306941Sdelphij int restore_pwd; 2402228753Smm 2403306941Sdelphij /* Nothing to do here if name is empty */ 2404306941Sdelphij if(path[0] == '\0') 2405306941Sdelphij return (ARCHIVE_OK); 2406306941Sdelphij 2407228753Smm /* 2408228753Smm * Guard against symlink tricks. Reject any archive entry whose 2409228753Smm * destination would be altered by a symlink. 2410306941Sdelphij * 2411306941Sdelphij * Walk the filename in chunks separated by '/'. For each segment: 2412306941Sdelphij * - if it doesn't exist, continue 2413306941Sdelphij * - if it's symlink, abort or remove it 2414306941Sdelphij * - if it's a directory and it's not the last chunk, cd into it 2415306941Sdelphij * As we go: 2416306941Sdelphij * head points to the current (relative) path 2417306941Sdelphij * tail points to the temporary \0 terminating the segment we're currently examining 2418306941Sdelphij * c holds what used to be in *tail 2419306941Sdelphij * last is 1 if this is the last tail 2420228753Smm */ 2421306941Sdelphij restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC); 2422306941Sdelphij __archive_ensure_cloexec_flag(restore_pwd); 2423306941Sdelphij if (restore_pwd < 0) 2424306941Sdelphij return (ARCHIVE_FATAL); 2425306941Sdelphij head = path; 2426306941Sdelphij tail = path; 2427306941Sdelphij last = 0; 2428306941Sdelphij /* TODO: reintroduce a safe cache here? */ 2429306941Sdelphij /* Skip the root directory if the path is absolute. */ 2430306941Sdelphij if(tail == path && tail[0] == '/') 2431306941Sdelphij ++tail; 2432306941Sdelphij /* Keep going until we've checked the entire name. 2433306941Sdelphij * head, tail, path all alias the same string, which is 2434306941Sdelphij * temporarily zeroed at tail, so be careful restoring the 2435306941Sdelphij * stashed (c=tail[0]) for error messages. 2436306941Sdelphij * Exiting the loop with break is okay; continue is not. 2437306941Sdelphij */ 2438306941Sdelphij while (!last) { 2439306941Sdelphij /* Skip the separator we just consumed, plus any adjacent ones */ 2440306941Sdelphij while (*tail == '/') 2441306941Sdelphij ++tail; 2442228753Smm /* Skip the next path element. */ 2443306941Sdelphij while (*tail != '\0' && *tail != '/') 2444306941Sdelphij ++tail; 2445306941Sdelphij /* is this the last path component? */ 2446306941Sdelphij last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0'); 2447306941Sdelphij /* temporarily truncate the string here */ 2448306941Sdelphij c = tail[0]; 2449306941Sdelphij tail[0] = '\0'; 2450228753Smm /* Check that we haven't hit a symlink. */ 2451306941Sdelphij r = lstat(head, &st); 2452228753Smm if (r != 0) { 2453306941Sdelphij tail[0] = c; 2454228753Smm /* We've hit a dir that doesn't exist; stop now. */ 2455306941Sdelphij if (errno == ENOENT) { 2456228753Smm break; 2457306941Sdelphij } else { 2458306941Sdelphij /* Treat any other error as fatal - best to be paranoid here 2459306941Sdelphij * Note: This effectively disables deep directory 2460306941Sdelphij * support when security checks are enabled. 2461306941Sdelphij * Otherwise, very long pathnames that trigger 2462306941Sdelphij * an error here could evade the sandbox. 2463306941Sdelphij * TODO: We could do better, but it would probably 2464306941Sdelphij * require merging the symlink checks with the 2465306941Sdelphij * deep-directory editing. */ 2466306941Sdelphij if (error_number) *error_number = errno; 2467306941Sdelphij if (error_string) 2468306941Sdelphij archive_string_sprintf(error_string, 2469306941Sdelphij "Could not stat %s", 2470306941Sdelphij path); 2471306941Sdelphij res = ARCHIVE_FAILED; 2472306941Sdelphij break; 2473306941Sdelphij } 2474306941Sdelphij } else if (S_ISDIR(st.st_mode)) { 2475306941Sdelphij if (!last) { 2476306941Sdelphij if (chdir(head) != 0) { 2477306941Sdelphij tail[0] = c; 2478306941Sdelphij if (error_number) *error_number = errno; 2479306941Sdelphij if (error_string) 2480306941Sdelphij archive_string_sprintf(error_string, 2481306941Sdelphij "Could not chdir %s", 2482306941Sdelphij path); 2483306941Sdelphij res = (ARCHIVE_FATAL); 2484306941Sdelphij break; 2485306941Sdelphij } 2486306941Sdelphij /* Our view is now from inside this dir: */ 2487306941Sdelphij head = tail + 1; 2488306941Sdelphij } 2489228753Smm } else if (S_ISLNK(st.st_mode)) { 2490306941Sdelphij if (last) { 2491228753Smm /* 2492228753Smm * Last element is symlink; remove it 2493228753Smm * so we can overwrite it with the 2494228753Smm * item being extracted. 2495228753Smm */ 2496306941Sdelphij if (unlink(head)) { 2497306941Sdelphij tail[0] = c; 2498306941Sdelphij if (error_number) *error_number = errno; 2499306941Sdelphij if (error_string) 2500306941Sdelphij archive_string_sprintf(error_string, 2501306941Sdelphij "Could not remove symlink %s", 2502306941Sdelphij path); 2503306941Sdelphij res = ARCHIVE_FAILED; 2504306941Sdelphij break; 2505228753Smm } 2506228753Smm /* 2507228753Smm * Even if we did remove it, a warning 2508228753Smm * is in order. The warning is silly, 2509228753Smm * though, if we're just replacing one 2510228753Smm * symlink with another symlink. 2511228753Smm */ 2512306941Sdelphij tail[0] = c; 2513306941Sdelphij /* FIXME: not sure how important this is to restore 2514306941Sdelphij if (!S_ISLNK(path)) { 2515306941Sdelphij if (error_number) *error_number = 0; 2516306941Sdelphij if (error_string) 2517306941Sdelphij archive_string_sprintf(error_string, 2518306941Sdelphij "Removing symlink %s", 2519306941Sdelphij path); 2520228753Smm } 2521306941Sdelphij */ 2522228753Smm /* Symlink gone. No more problem! */ 2523306941Sdelphij res = ARCHIVE_OK; 2524306941Sdelphij break; 2525306941Sdelphij } else if (flags & ARCHIVE_EXTRACT_UNLINK) { 2526228753Smm /* User asked us to remove problems. */ 2527306941Sdelphij if (unlink(head) != 0) { 2528306941Sdelphij tail[0] = c; 2529306941Sdelphij if (error_number) *error_number = 0; 2530306941Sdelphij if (error_string) 2531306941Sdelphij archive_string_sprintf(error_string, 2532306941Sdelphij "Cannot remove intervening symlink %s", 2533306941Sdelphij path); 2534306941Sdelphij res = ARCHIVE_FAILED; 2535306941Sdelphij break; 2536228753Smm } 2537306941Sdelphij tail[0] = c; 2538228753Smm } else { 2539306941Sdelphij tail[0] = c; 2540306941Sdelphij if (error_number) *error_number = 0; 2541306941Sdelphij if (error_string) 2542306941Sdelphij archive_string_sprintf(error_string, 2543306941Sdelphij "Cannot extract through symlink %s", 2544306941Sdelphij path); 2545306941Sdelphij res = ARCHIVE_FAILED; 2546306941Sdelphij break; 2547228753Smm } 2548228753Smm } 2549306941Sdelphij /* be sure to always maintain this */ 2550306941Sdelphij tail[0] = c; 2551306941Sdelphij if (tail[0] != '\0') 2552306941Sdelphij tail++; /* Advance to the next segment. */ 2553228753Smm } 2554306941Sdelphij /* Catches loop exits via break */ 2555306941Sdelphij tail[0] = c; 2556306941Sdelphij#ifdef HAVE_FCHDIR 2557306941Sdelphij /* If we changed directory above, restore it here. */ 2558306941Sdelphij if (restore_pwd >= 0) { 2559306941Sdelphij r = fchdir(restore_pwd); 2560306941Sdelphij if (r != 0) { 2561306941Sdelphij if(error_number) *error_number = errno; 2562306941Sdelphij if(error_string) 2563306941Sdelphij archive_string_sprintf(error_string, 2564306941Sdelphij "chdir() failure"); 2565306941Sdelphij } 2566306941Sdelphij close(restore_pwd); 2567306941Sdelphij restore_pwd = -1; 2568306941Sdelphij if (r != 0) { 2569306941Sdelphij res = (ARCHIVE_FATAL); 2570306941Sdelphij } 2571306941Sdelphij } 2572228753Smm#endif 2573306941Sdelphij /* TODO: reintroduce a safe cache here? */ 2574306941Sdelphij return res; 2575306941Sdelphij#endif 2576228753Smm} 2577228753Smm 2578306941Sdelphij/* 2579306941Sdelphij * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise 2580306941Sdelphij * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED} 2581306941Sdelphij */ 2582306941Sdelphijstatic int 2583306941Sdelphijcheck_symlinks(struct archive_write_disk *a) 2584306941Sdelphij{ 2585306941Sdelphij struct archive_string error_string; 2586306941Sdelphij int error_number; 2587306941Sdelphij int rc; 2588306941Sdelphij archive_string_init(&error_string); 2589306941Sdelphij rc = check_symlinks_fsobj(a->name, &error_number, &error_string, a->flags); 2590306941Sdelphij if (rc != ARCHIVE_OK) { 2591306941Sdelphij archive_set_error(&a->archive, error_number, "%s", error_string.s); 2592306941Sdelphij } 2593306941Sdelphij archive_string_free(&error_string); 2594306941Sdelphij a->pst = NULL; /* to be safe */ 2595306941Sdelphij return rc; 2596306941Sdelphij} 2597306941Sdelphij 2598306941Sdelphij 2599231200Smm#if defined(__CYGWIN__) 2600228753Smm/* 2601228753Smm * 1. Convert a path separator from '\' to '/' . 2602231200Smm * We shouldn't check multibyte character directly because some 2603228753Smm * character-set have been using the '\' character for a part of 2604228753Smm * its multibyte character code. 2605228753Smm * 2. Replace unusable characters in Windows with underscore('_'). 2606228753Smm * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx 2607228753Smm */ 2608231200Smmstatic void 2609228753Smmcleanup_pathname_win(struct archive_write_disk *a) 2610228753Smm{ 2611228753Smm wchar_t wc; 2612228753Smm char *p; 2613228753Smm size_t alen, l; 2614231200Smm int mb, complete, utf8; 2615228753Smm 2616231200Smm alen = 0; 2617231200Smm mb = 0; 2618231200Smm complete = 1; 2619231200Smm utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0; 2620231200Smm for (p = a->name; *p != '\0'; p++) { 2621231200Smm ++alen; 2622231200Smm if (*p == '\\') { 2623231200Smm /* If previous byte is smaller than 128, 2624231200Smm * this is not second byte of multibyte characters, 2625231200Smm * so we can replace '\' with '/'. */ 2626231200Smm if (utf8 || !mb) 2627231200Smm *p = '/'; 2628228753Smm else 2629231200Smm complete = 0;/* uncompleted. */ 2630231200Smm } else if (*(unsigned char *)p > 127) 2631231200Smm mb = 1; 2632231200Smm else 2633231200Smm mb = 0; 2634231200Smm /* Rewrite the path name if its next character is unusable. */ 2635228753Smm if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || 2636228753Smm *p == '<' || *p == '>' || *p == '|') 2637228753Smm *p = '_'; 2638228753Smm } 2639231200Smm if (complete) 2640231200Smm return; 2641231200Smm 2642228753Smm /* 2643231200Smm * Convert path separator in wide-character. 2644228753Smm */ 2645228753Smm p = a->name; 2646228753Smm while (*p != '\0' && alen) { 2647228753Smm l = mbtowc(&wc, p, alen); 2648232153Smm if (l == (size_t)-1) { 2649228753Smm while (*p != '\0') { 2650228753Smm if (*p == '\\') 2651228753Smm *p = '/'; 2652228753Smm ++p; 2653228753Smm } 2654228753Smm break; 2655228753Smm } 2656228753Smm if (l == 1 && wc == L'\\') 2657228753Smm *p = '/'; 2658228753Smm p += l; 2659228753Smm alen -= l; 2660228753Smm } 2661228753Smm} 2662228753Smm#endif 2663228753Smm 2664228753Smm/* 2665228753Smm * Canonicalize the pathname. In particular, this strips duplicate 2666228753Smm * '/' characters, '.' elements, and trailing '/'. It also raises an 2667301046Sglebius * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is 2668301046Sglebius * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS 2669301046Sglebius * is set) if the path is absolute. 2670228753Smm */ 2671228753Smmstatic int 2672306941Sdelphijcleanup_pathname_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags) 2673228753Smm{ 2674228753Smm char *dest, *src; 2675228753Smm char separator = '\0'; 2676228753Smm 2677306941Sdelphij dest = src = path; 2678228753Smm if (*src == '\0') { 2679306941Sdelphij if (error_number) *error_number = ARCHIVE_ERRNO_MISC; 2680306941Sdelphij if (error_string) 2681306941Sdelphij archive_string_sprintf(error_string, 2682306941Sdelphij "Invalid empty pathname"); 2683228753Smm return (ARCHIVE_FAILED); 2684228753Smm } 2685228753Smm 2686231200Smm#if defined(__CYGWIN__) 2687231200Smm cleanup_pathname_win(a); 2688228753Smm#endif 2689228753Smm /* Skip leading '/'. */ 2690301046Sglebius if (*src == '/') { 2691306941Sdelphij if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) { 2692306941Sdelphij if (error_number) *error_number = ARCHIVE_ERRNO_MISC; 2693306941Sdelphij if (error_string) 2694306941Sdelphij archive_string_sprintf(error_string, 2695306941Sdelphij "Path is absolute"); 2696301046Sglebius return (ARCHIVE_FAILED); 2697301046Sglebius } 2698301046Sglebius 2699228753Smm separator = *src++; 2700301046Sglebius } 2701228753Smm 2702228753Smm /* Scan the pathname one element at a time. */ 2703228753Smm for (;;) { 2704228753Smm /* src points to first char after '/' */ 2705228753Smm if (src[0] == '\0') { 2706228753Smm break; 2707228753Smm } else if (src[0] == '/') { 2708228753Smm /* Found '//', ignore second one. */ 2709228753Smm src++; 2710228753Smm continue; 2711228753Smm } else if (src[0] == '.') { 2712228753Smm if (src[1] == '\0') { 2713228753Smm /* Ignore trailing '.' */ 2714228753Smm break; 2715228753Smm } else if (src[1] == '/') { 2716228753Smm /* Skip './'. */ 2717228753Smm src += 2; 2718228753Smm continue; 2719228753Smm } else if (src[1] == '.') { 2720228753Smm if (src[2] == '/' || src[2] == '\0') { 2721228753Smm /* Conditionally warn about '..' */ 2722306941Sdelphij if (flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) { 2723306941Sdelphij if (error_number) *error_number = ARCHIVE_ERRNO_MISC; 2724306941Sdelphij if (error_string) 2725306941Sdelphij archive_string_sprintf(error_string, 2726306941Sdelphij "Path contains '..'"); 2727228753Smm return (ARCHIVE_FAILED); 2728228753Smm } 2729228753Smm } 2730228753Smm /* 2731228753Smm * Note: Under no circumstances do we 2732228753Smm * remove '..' elements. In 2733228753Smm * particular, restoring 2734228753Smm * '/foo/../bar/' should create the 2735228753Smm * 'foo' dir as a side-effect. 2736228753Smm */ 2737228753Smm } 2738228753Smm } 2739228753Smm 2740228753Smm /* Copy current element, including leading '/'. */ 2741228753Smm if (separator) 2742228753Smm *dest++ = '/'; 2743228753Smm while (*src != '\0' && *src != '/') { 2744228753Smm *dest++ = *src++; 2745228753Smm } 2746228753Smm 2747228753Smm if (*src == '\0') 2748228753Smm break; 2749228753Smm 2750228753Smm /* Skip '/' separator. */ 2751228753Smm separator = *src++; 2752228753Smm } 2753228753Smm /* 2754228753Smm * We've just copied zero or more path elements, not including the 2755228753Smm * final '/'. 2756228753Smm */ 2757306941Sdelphij if (dest == path) { 2758228753Smm /* 2759228753Smm * Nothing got copied. The path must have been something 2760228753Smm * like '.' or '/' or './' or '/././././/./'. 2761228753Smm */ 2762228753Smm if (separator) 2763228753Smm *dest++ = '/'; 2764228753Smm else 2765228753Smm *dest++ = '.'; 2766228753Smm } 2767228753Smm /* Terminate the result. */ 2768228753Smm *dest = '\0'; 2769228753Smm return (ARCHIVE_OK); 2770228753Smm} 2771228753Smm 2772306941Sdelphijstatic int 2773306941Sdelphijcleanup_pathname(struct archive_write_disk *a) 2774306941Sdelphij{ 2775306941Sdelphij struct archive_string error_string; 2776306941Sdelphij int error_number; 2777306941Sdelphij int rc; 2778306941Sdelphij archive_string_init(&error_string); 2779306941Sdelphij rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string, a->flags); 2780306941Sdelphij if (rc != ARCHIVE_OK) { 2781306941Sdelphij archive_set_error(&a->archive, error_number, "%s", error_string.s); 2782306941Sdelphij } 2783306941Sdelphij archive_string_free(&error_string); 2784306941Sdelphij return rc; 2785306941Sdelphij} 2786306941Sdelphij 2787228753Smm/* 2788228753Smm * Create the parent directory of the specified path, assuming path 2789228753Smm * is already in mutable storage. 2790228753Smm */ 2791228753Smmstatic int 2792228753Smmcreate_parent_dir(struct archive_write_disk *a, char *path) 2793228753Smm{ 2794228753Smm char *slash; 2795228753Smm int r; 2796228753Smm 2797228753Smm /* Remove tail element to obtain parent name. */ 2798228753Smm slash = strrchr(path, '/'); 2799228753Smm if (slash == NULL) 2800228753Smm return (ARCHIVE_OK); 2801228753Smm *slash = '\0'; 2802228753Smm r = create_dir(a, path); 2803228753Smm *slash = '/'; 2804228753Smm return (r); 2805228753Smm} 2806228753Smm 2807228753Smm/* 2808228753Smm * Create the specified dir, recursing to create parents as necessary. 2809228753Smm * 2810228753Smm * Returns ARCHIVE_OK if the path exists when we're done here. 2811228753Smm * Otherwise, returns ARCHIVE_FAILED. 2812228753Smm * Assumes path is in mutable storage; path is unchanged on exit. 2813228753Smm */ 2814228753Smmstatic int 2815228753Smmcreate_dir(struct archive_write_disk *a, char *path) 2816228753Smm{ 2817228753Smm struct stat st; 2818228753Smm struct fixup_entry *le; 2819228753Smm char *slash, *base; 2820228753Smm mode_t mode_final, mode; 2821228753Smm int r; 2822228753Smm 2823228753Smm /* Check for special names and just skip them. */ 2824228753Smm slash = strrchr(path, '/'); 2825228753Smm if (slash == NULL) 2826228753Smm base = path; 2827228753Smm else 2828228753Smm base = slash + 1; 2829228753Smm 2830228753Smm if (base[0] == '\0' || 2831228753Smm (base[0] == '.' && base[1] == '\0') || 2832228753Smm (base[0] == '.' && base[1] == '.' && base[2] == '\0')) { 2833228753Smm /* Don't bother trying to create null path, '.', or '..'. */ 2834228753Smm if (slash != NULL) { 2835228753Smm *slash = '\0'; 2836228753Smm r = create_dir(a, path); 2837228753Smm *slash = '/'; 2838228753Smm return (r); 2839228753Smm } 2840228753Smm return (ARCHIVE_OK); 2841228753Smm } 2842228753Smm 2843228753Smm /* 2844228753Smm * Yes, this should be stat() and not lstat(). Using lstat() 2845228753Smm * here loses the ability to extract through symlinks. Also note 2846228753Smm * that this should not use the a->st cache. 2847228753Smm */ 2848228753Smm if (stat(path, &st) == 0) { 2849228753Smm if (S_ISDIR(st.st_mode)) 2850228753Smm return (ARCHIVE_OK); 2851228753Smm if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { 2852228753Smm archive_set_error(&a->archive, EEXIST, 2853228753Smm "Can't create directory '%s'", path); 2854228753Smm return (ARCHIVE_FAILED); 2855228753Smm } 2856228753Smm if (unlink(path) != 0) { 2857228753Smm archive_set_error(&a->archive, errno, 2858228753Smm "Can't create directory '%s': " 2859231200Smm "Conflicting file cannot be removed", 2860231200Smm path); 2861228753Smm return (ARCHIVE_FAILED); 2862228753Smm } 2863228753Smm } else if (errno != ENOENT && errno != ENOTDIR) { 2864228753Smm /* Stat failed? */ 2865228753Smm archive_set_error(&a->archive, errno, "Can't test directory '%s'", path); 2866228753Smm return (ARCHIVE_FAILED); 2867228753Smm } else if (slash != NULL) { 2868228753Smm *slash = '\0'; 2869228753Smm r = create_dir(a, path); 2870228753Smm *slash = '/'; 2871228753Smm if (r != ARCHIVE_OK) 2872228753Smm return (r); 2873228753Smm } 2874228753Smm 2875228753Smm /* 2876228753Smm * Mode we want for the final restored directory. Per POSIX, 2877228753Smm * implicitly-created dirs must be created obeying the umask. 2878228753Smm * There's no mention whether this is different for privileged 2879228753Smm * restores (which the rest of this code handles by pretending 2880228753Smm * umask=0). I've chosen here to always obey the user's umask for 2881228753Smm * implicit dirs, even if _EXTRACT_PERM was specified. 2882228753Smm */ 2883228753Smm mode_final = DEFAULT_DIR_MODE & ~a->user_umask; 2884228753Smm /* Mode we want on disk during the restore process. */ 2885228753Smm mode = mode_final; 2886228753Smm mode |= MINIMUM_DIR_MODE; 2887228753Smm mode &= MAXIMUM_DIR_MODE; 2888228753Smm if (mkdir(path, mode) == 0) { 2889228753Smm if (mode != mode_final) { 2890228753Smm le = new_fixup(a, path); 2891248616Smm if (le == NULL) 2892248616Smm return (ARCHIVE_FATAL); 2893228753Smm le->fixup |=TODO_MODE_BASE; 2894228753Smm le->mode = mode_final; 2895228753Smm } 2896228753Smm return (ARCHIVE_OK); 2897228753Smm } 2898228753Smm 2899228753Smm /* 2900228753Smm * Without the following check, a/b/../b/c/d fails at the 2901228753Smm * second visit to 'b', so 'd' can't be created. Note that we 2902228753Smm * don't add it to the fixup list here, as it's already been 2903228753Smm * added. 2904228753Smm */ 2905228753Smm if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) 2906228753Smm return (ARCHIVE_OK); 2907228753Smm 2908228753Smm archive_set_error(&a->archive, errno, "Failed to create dir '%s'", 2909228753Smm path); 2910228753Smm return (ARCHIVE_FAILED); 2911228753Smm} 2912228753Smm 2913228753Smm/* 2914228753Smm * Note: Although we can skip setting the user id if the desired user 2915228753Smm * id matches the current user, we cannot skip setting the group, as 2916228753Smm * many systems set the gid based on the containing directory. So 2917228753Smm * we have to perform a chown syscall if we want to set the SGID 2918228753Smm * bit. (The alternative is to stat() and then possibly chown(); it's 2919228753Smm * more efficient to skip the stat() and just always chown().) Note 2920228753Smm * that a successful chown() here clears the TODO_SGID_CHECK bit, which 2921228753Smm * allows set_mode to skip the stat() check for the GID. 2922228753Smm */ 2923228753Smmstatic int 2924228753Smmset_ownership(struct archive_write_disk *a) 2925228753Smm{ 2926228753Smm#ifndef __CYGWIN__ 2927228753Smm/* unfortunately, on win32 there is no 'root' user with uid 0, 2928228753Smm so we just have to try the chown and see if it works */ 2929228753Smm 2930228753Smm /* If we know we can't change it, don't bother trying. */ 2931228753Smm if (a->user_uid != 0 && a->user_uid != a->uid) { 2932228753Smm archive_set_error(&a->archive, errno, 2933231200Smm "Can't set UID=%jd", (intmax_t)a->uid); 2934228753Smm return (ARCHIVE_WARN); 2935228753Smm } 2936228753Smm#endif 2937228753Smm 2938228753Smm#ifdef HAVE_FCHOWN 2939228753Smm /* If we have an fd, we can avoid a race. */ 2940228753Smm if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) { 2941228753Smm /* We've set owner and know uid/gid are correct. */ 2942228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 2943228753Smm return (ARCHIVE_OK); 2944228753Smm } 2945228753Smm#endif 2946228753Smm 2947228753Smm /* We prefer lchown() but will use chown() if that's all we have. */ 2948228753Smm /* Of course, if we have neither, this will always fail. */ 2949228753Smm#ifdef HAVE_LCHOWN 2950228753Smm if (lchown(a->name, a->uid, a->gid) == 0) { 2951228753Smm /* We've set owner and know uid/gid are correct. */ 2952228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 2953228753Smm return (ARCHIVE_OK); 2954228753Smm } 2955228753Smm#elif HAVE_CHOWN 2956228753Smm if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) { 2957228753Smm /* We've set owner and know uid/gid are correct. */ 2958228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 2959228753Smm return (ARCHIVE_OK); 2960228753Smm } 2961228753Smm#endif 2962228753Smm 2963228753Smm archive_set_error(&a->archive, errno, 2964231200Smm "Can't set user=%jd/group=%jd for %s", 2965231200Smm (intmax_t)a->uid, (intmax_t)a->gid, a->name); 2966228753Smm return (ARCHIVE_WARN); 2967228753Smm} 2968228753Smm 2969231200Smm/* 2970231200Smm * Note: Returns 0 on success, non-zero on failure. 2971228753Smm */ 2972228753Smmstatic int 2973228753Smmset_time(int fd, int mode, const char *name, 2974228753Smm time_t atime, long atime_nsec, 2975228753Smm time_t mtime, long mtime_nsec) 2976228753Smm{ 2977231200Smm /* Select the best implementation for this platform. */ 2978231200Smm#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS) 2979231200Smm /* 2980231200Smm * utimensat() and futimens() are defined in 2981231200Smm * POSIX.1-2008. They support ns resolution and setting times 2982231200Smm * on fds and symlinks. 2983231200Smm */ 2984228753Smm struct timespec ts[2]; 2985232153Smm (void)mode; /* UNUSED */ 2986228753Smm ts[0].tv_sec = atime; 2987228753Smm ts[0].tv_nsec = atime_nsec; 2988228753Smm ts[1].tv_sec = mtime; 2989228753Smm ts[1].tv_nsec = mtime_nsec; 2990228753Smm if (fd >= 0) 2991228753Smm return futimens(fd, ts); 2992228753Smm return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW); 2993231200Smm 2994228753Smm#elif HAVE_UTIMES 2995231200Smm /* 2996231200Smm * The utimes()-family functions support ��s-resolution and 2997231200Smm * setting times fds and symlinks. utimes() is documented as 2998231200Smm * LEGACY by POSIX, futimes() and lutimes() are not described 2999231200Smm * in POSIX. 3000231200Smm */ 3001228753Smm struct timeval times[2]; 3002228753Smm 3003228753Smm times[0].tv_sec = atime; 3004228753Smm times[0].tv_usec = atime_nsec / 1000; 3005228753Smm times[1].tv_sec = mtime; 3006228753Smm times[1].tv_usec = mtime_nsec / 1000; 3007228753Smm 3008228753Smm#ifdef HAVE_FUTIMES 3009228753Smm if (fd >= 0) 3010228753Smm return (futimes(fd, times)); 3011228753Smm#else 3012228753Smm (void)fd; /* UNUSED */ 3013228753Smm#endif 3014228753Smm#ifdef HAVE_LUTIMES 3015228753Smm (void)mode; /* UNUSED */ 3016228753Smm return (lutimes(name, times)); 3017228753Smm#else 3018228753Smm if (S_ISLNK(mode)) 3019228753Smm return (0); 3020228753Smm return (utimes(name, times)); 3021228753Smm#endif 3022231200Smm 3023228753Smm#elif defined(HAVE_UTIME) 3024231200Smm /* 3025231200Smm * utime() is POSIX-standard but only supports 1s resolution and 3026231200Smm * does not support fds or symlinks. 3027231200Smm */ 3028228753Smm struct utimbuf times; 3029228753Smm (void)fd; /* UNUSED */ 3030228753Smm (void)name; /* UNUSED */ 3031228753Smm (void)atime_nsec; /* UNUSED */ 3032228753Smm (void)mtime_nsec; /* UNUSED */ 3033228753Smm times.actime = atime; 3034228753Smm times.modtime = mtime; 3035228753Smm if (S_ISLNK(mode)) 3036228753Smm return (ARCHIVE_OK); 3037228753Smm return (utime(name, ×)); 3038231200Smm 3039231200Smm#else 3040231200Smm /* 3041231200Smm * We don't know how to set the time on this platform. 3042231200Smm */ 3043232153Smm (void)fd; /* UNUSED */ 3044232153Smm (void)mode; /* UNUSED */ 3045232153Smm (void)name; /* UNUSED */ 3046232153Smm (void)atime_nsec; /* UNUSED */ 3047232153Smm (void)mtime_nsec; /* UNUSED */ 3048231200Smm return (ARCHIVE_WARN); 3049231200Smm#endif 3050228753Smm} 3051231200Smm 3052231200Smm#ifdef F_SETTIMES /* Tru64 */ 3053228753Smmstatic int 3054231200Smmset_time_tru64(int fd, int mode, const char *name, 3055228753Smm time_t atime, long atime_nsec, 3056231200Smm time_t mtime, long mtime_nsec, 3057231200Smm time_t ctime, long ctime_nsec) 3058228753Smm{ 3059231200Smm struct attr_timbuf tstamp; 3060231200Smm struct timeval times[3]; 3061231200Smm times[0].tv_sec = atime; 3062231200Smm times[0].tv_usec = atime_nsec / 1000; 3063231200Smm times[1].tv_sec = mtime; 3064231200Smm times[1].tv_usec = mtime_nsec / 1000; 3065231200Smm times[2].tv_sec = ctime; 3066231200Smm times[2].tv_usec = ctime_nsec / 1000; 3067231200Smm tstamp.atime = times[0]; 3068231200Smm tstamp.mtime = times[1]; 3069231200Smm tstamp.ctime = times[2]; 3070231200Smm return (fcntl(fd,F_SETTIMES,&tstamp)); 3071228753Smm} 3072231200Smm#endif /* Tru64 */ 3073231200Smm 3074231200Smmstatic int 3075231200Smmset_times(struct archive_write_disk *a, 3076231200Smm int fd, int mode, const char *name, 3077231200Smm time_t atime, long atime_nanos, 3078231200Smm time_t birthtime, long birthtime_nanos, 3079231200Smm time_t mtime, long mtime_nanos, 3080232153Smm time_t cctime, long ctime_nanos) 3081231200Smm{ 3082231200Smm /* Note: set_time doesn't use libarchive return conventions! 3083231200Smm * It uses syscall conventions. So 0 here instead of ARCHIVE_OK. */ 3084231200Smm int r1 = 0, r2 = 0; 3085231200Smm 3086231200Smm#ifdef F_SETTIMES 3087231200Smm /* 3088231200Smm * on Tru64 try own fcntl first which can restore even the 3089231200Smm * ctime, fall back to default code path below if it fails 3090231200Smm * or if we are not running as root 3091231200Smm */ 3092231200Smm if (a->user_uid == 0 && 3093231200Smm set_time_tru64(fd, mode, name, 3094231200Smm atime, atime_nanos, mtime, 3095232153Smm mtime_nanos, cctime, ctime_nanos) == 0) { 3096231200Smm return (ARCHIVE_OK); 3097231200Smm } 3098232153Smm#else /* Tru64 */ 3099232153Smm (void)cctime; /* UNUSED */ 3100232153Smm (void)ctime_nanos; /* UNUSED */ 3101231200Smm#endif /* Tru64 */ 3102231200Smm 3103231200Smm#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME 3104231200Smm /* 3105231200Smm * If you have struct stat.st_birthtime, we assume BSD 3106231200Smm * birthtime semantics, in which {f,l,}utimes() updates 3107231200Smm * birthtime to earliest mtime. So we set the time twice, 3108231200Smm * first using the birthtime, then using the mtime. If 3109231200Smm * birthtime == mtime, this isn't necessary, so we skip it. 3110231200Smm * If birthtime > mtime, then this won't work, so we skip it. 3111231200Smm */ 3112231200Smm if (birthtime < mtime 3113231200Smm || (birthtime == mtime && birthtime_nanos < mtime_nanos)) 3114231200Smm r1 = set_time(fd, mode, name, 3115231200Smm atime, atime_nanos, 3116231200Smm birthtime, birthtime_nanos); 3117232153Smm#else 3118232153Smm (void)birthtime; /* UNUSED */ 3119232153Smm (void)birthtime_nanos; /* UNUSED */ 3120228753Smm#endif 3121231200Smm r2 = set_time(fd, mode, name, 3122231200Smm atime, atime_nanos, 3123231200Smm mtime, mtime_nanos); 3124231200Smm if (r1 != 0 || r2 != 0) { 3125231200Smm archive_set_error(&a->archive, errno, 3126231200Smm "Can't restore time"); 3127231200Smm return (ARCHIVE_WARN); 3128231200Smm } 3129231200Smm return (ARCHIVE_OK); 3130231200Smm} 3131228753Smm 3132228753Smmstatic int 3133231200Smmset_times_from_entry(struct archive_write_disk *a) 3134228753Smm{ 3135232153Smm time_t atime, birthtime, mtime, cctime; 3136231200Smm long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec; 3137228753Smm 3138231200Smm /* Suitable defaults. */ 3139232153Smm atime = birthtime = mtime = cctime = a->start_time; 3140231200Smm atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0; 3141231200Smm 3142228753Smm /* If no time was provided, we're done. */ 3143228753Smm if (!archive_entry_atime_is_set(a->entry) 3144228753Smm#if HAVE_STRUCT_STAT_ST_BIRTHTIME 3145228753Smm && !archive_entry_birthtime_is_set(a->entry) 3146228753Smm#endif 3147228753Smm && !archive_entry_mtime_is_set(a->entry)) 3148228753Smm return (ARCHIVE_OK); 3149228753Smm 3150228753Smm if (archive_entry_atime_is_set(a->entry)) { 3151228753Smm atime = archive_entry_atime(a->entry); 3152228753Smm atime_nsec = archive_entry_atime_nsec(a->entry); 3153228753Smm } 3154231200Smm if (archive_entry_birthtime_is_set(a->entry)) { 3155231200Smm birthtime = archive_entry_birthtime(a->entry); 3156231200Smm birthtime_nsec = archive_entry_birthtime_nsec(a->entry); 3157231200Smm } 3158228753Smm if (archive_entry_mtime_is_set(a->entry)) { 3159228753Smm mtime = archive_entry_mtime(a->entry); 3160228753Smm mtime_nsec = archive_entry_mtime_nsec(a->entry); 3161228753Smm } 3162231200Smm if (archive_entry_ctime_is_set(a->entry)) { 3163232153Smm cctime = archive_entry_ctime(a->entry); 3164231200Smm ctime_nsec = archive_entry_ctime_nsec(a->entry); 3165228753Smm } 3166228753Smm 3167231200Smm return set_times(a, a->fd, a->mode, a->name, 3168231200Smm atime, atime_nsec, 3169231200Smm birthtime, birthtime_nsec, 3170231200Smm mtime, mtime_nsec, 3171232153Smm cctime, ctime_nsec); 3172228753Smm} 3173228753Smm 3174228753Smmstatic int 3175228753Smmset_mode(struct archive_write_disk *a, int mode) 3176228753Smm{ 3177228753Smm int r = ARCHIVE_OK; 3178228753Smm mode &= 07777; /* Strip off file type bits. */ 3179228753Smm 3180228753Smm if (a->todo & TODO_SGID_CHECK) { 3181228753Smm /* 3182228753Smm * If we don't know the GID is right, we must stat() 3183228753Smm * to verify it. We can't just check the GID of this 3184228753Smm * process, since systems sometimes set GID from 3185228753Smm * the enclosing dir or based on ACLs. 3186228753Smm */ 3187231200Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 3188228753Smm return (r); 3189228753Smm if (a->pst->st_gid != a->gid) { 3190228753Smm mode &= ~ S_ISGID; 3191228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 3192228753Smm /* 3193228753Smm * This is only an error if you 3194228753Smm * requested owner restore. If you 3195228753Smm * didn't, we'll try to restore 3196228753Smm * sgid/suid, but won't consider it a 3197228753Smm * problem if we can't. 3198228753Smm */ 3199228753Smm archive_set_error(&a->archive, -1, 3200228753Smm "Can't restore SGID bit"); 3201228753Smm r = ARCHIVE_WARN; 3202228753Smm } 3203228753Smm } 3204228753Smm /* While we're here, double-check the UID. */ 3205228753Smm if (a->pst->st_uid != a->uid 3206228753Smm && (a->todo & TODO_SUID)) { 3207228753Smm mode &= ~ S_ISUID; 3208228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 3209228753Smm archive_set_error(&a->archive, -1, 3210228753Smm "Can't restore SUID bit"); 3211228753Smm r = ARCHIVE_WARN; 3212228753Smm } 3213228753Smm } 3214228753Smm a->todo &= ~TODO_SGID_CHECK; 3215228753Smm a->todo &= ~TODO_SUID_CHECK; 3216228753Smm } else if (a->todo & TODO_SUID_CHECK) { 3217228753Smm /* 3218228753Smm * If we don't know the UID is right, we can just check 3219228753Smm * the user, since all systems set the file UID from 3220228753Smm * the process UID. 3221228753Smm */ 3222228753Smm if (a->user_uid != a->uid) { 3223228753Smm mode &= ~ S_ISUID; 3224228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 3225228753Smm archive_set_error(&a->archive, -1, 3226228753Smm "Can't make file SUID"); 3227228753Smm r = ARCHIVE_WARN; 3228228753Smm } 3229228753Smm } 3230228753Smm a->todo &= ~TODO_SUID_CHECK; 3231228753Smm } 3232228753Smm 3233228753Smm if (S_ISLNK(a->mode)) { 3234228753Smm#ifdef HAVE_LCHMOD 3235228753Smm /* 3236228753Smm * If this is a symlink, use lchmod(). If the 3237228753Smm * platform doesn't support lchmod(), just skip it. A 3238228753Smm * platform that doesn't provide a way to set 3239228753Smm * permissions on symlinks probably ignores 3240228753Smm * permissions on symlinks, so a failure here has no 3241228753Smm * impact. 3242228753Smm */ 3243228753Smm if (lchmod(a->name, mode) != 0) { 3244228753Smm archive_set_error(&a->archive, errno, 3245228753Smm "Can't set permissions to 0%o", (int)mode); 3246228753Smm r = ARCHIVE_WARN; 3247228753Smm } 3248228753Smm#endif 3249228753Smm } else if (!S_ISDIR(a->mode)) { 3250228753Smm /* 3251228753Smm * If it's not a symlink and not a dir, then use 3252228753Smm * fchmod() or chmod(), depending on whether we have 3253228753Smm * an fd. Dirs get their perms set during the 3254228753Smm * post-extract fixup, which is handled elsewhere. 3255228753Smm */ 3256228753Smm#ifdef HAVE_FCHMOD 3257228753Smm if (a->fd >= 0) { 3258228753Smm if (fchmod(a->fd, mode) != 0) { 3259228753Smm archive_set_error(&a->archive, errno, 3260228753Smm "Can't set permissions to 0%o", (int)mode); 3261228753Smm r = ARCHIVE_WARN; 3262228753Smm } 3263228753Smm } else 3264228753Smm#endif 3265228753Smm /* If this platform lacks fchmod(), then 3266228753Smm * we'll just use chmod(). */ 3267228753Smm if (chmod(a->name, mode) != 0) { 3268228753Smm archive_set_error(&a->archive, errno, 3269228753Smm "Can't set permissions to 0%o", (int)mode); 3270228753Smm r = ARCHIVE_WARN; 3271228753Smm } 3272228753Smm } 3273228753Smm return (r); 3274228753Smm} 3275228753Smm 3276228753Smmstatic int 3277228753Smmset_fflags(struct archive_write_disk *a) 3278228753Smm{ 3279228753Smm struct fixup_entry *le; 3280228753Smm unsigned long set, clear; 3281228753Smm int r; 3282228753Smm int critical_flags; 3283228753Smm mode_t mode = archive_entry_mode(a->entry); 3284228753Smm 3285228753Smm /* 3286228753Smm * Make 'critical_flags' hold all file flags that can't be 3287228753Smm * immediately restored. For example, on BSD systems, 3288228753Smm * SF_IMMUTABLE prevents hardlinks from being created, so 3289228753Smm * should not be set until after any hardlinks are created. To 3290228753Smm * preserve some semblance of portability, this uses #ifdef 3291228753Smm * extensively. Ugly, but it works. 3292228753Smm * 3293228753Smm * Yes, Virginia, this does create a security race. It's mitigated 3294228753Smm * somewhat by the practice of creating dirs 0700 until the extract 3295228753Smm * is done, but it would be nice if we could do more than that. 3296228753Smm * People restoring critical file systems should be wary of 3297228753Smm * other programs that might try to muck with files as they're 3298228753Smm * being restored. 3299228753Smm */ 3300228753Smm /* Hopefully, the compiler will optimize this mess into a constant. */ 3301228753Smm critical_flags = 0; 3302228753Smm#ifdef SF_IMMUTABLE 3303228753Smm critical_flags |= SF_IMMUTABLE; 3304228753Smm#endif 3305228753Smm#ifdef UF_IMMUTABLE 3306228753Smm critical_flags |= UF_IMMUTABLE; 3307228753Smm#endif 3308228753Smm#ifdef SF_APPEND 3309228753Smm critical_flags |= SF_APPEND; 3310228753Smm#endif 3311228753Smm#ifdef UF_APPEND 3312228753Smm critical_flags |= UF_APPEND; 3313228753Smm#endif 3314228753Smm#ifdef EXT2_APPEND_FL 3315228753Smm critical_flags |= EXT2_APPEND_FL; 3316228753Smm#endif 3317228753Smm#ifdef EXT2_IMMUTABLE_FL 3318228753Smm critical_flags |= EXT2_IMMUTABLE_FL; 3319228753Smm#endif 3320228753Smm 3321228753Smm if (a->todo & TODO_FFLAGS) { 3322228753Smm archive_entry_fflags(a->entry, &set, &clear); 3323228753Smm 3324228753Smm /* 3325228753Smm * The first test encourages the compiler to eliminate 3326228753Smm * all of this if it's not necessary. 3327228753Smm */ 3328228753Smm if ((critical_flags != 0) && (set & critical_flags)) { 3329228753Smm le = current_fixup(a, a->name); 3330248616Smm if (le == NULL) 3331248616Smm return (ARCHIVE_FATAL); 3332228753Smm le->fixup |= TODO_FFLAGS; 3333228753Smm le->fflags_set = set; 3334228753Smm /* Store the mode if it's not already there. */ 3335228753Smm if ((le->fixup & TODO_MODE) == 0) 3336228753Smm le->mode = mode; 3337228753Smm } else { 3338228753Smm r = set_fflags_platform(a, a->fd, 3339228753Smm a->name, mode, set, clear); 3340228753Smm if (r != ARCHIVE_OK) 3341228753Smm return (r); 3342228753Smm } 3343228753Smm } 3344228753Smm return (ARCHIVE_OK); 3345228753Smm} 3346228753Smm 3347228753Smm 3348228753Smm#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS) 3349228753Smm/* 3350228753Smm * BSD reads flags using stat() and sets them with one of {f,l,}chflags() 3351228753Smm */ 3352228753Smmstatic int 3353228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 3354228753Smm mode_t mode, unsigned long set, unsigned long clear) 3355228753Smm{ 3356228753Smm int r; 3357228753Smm 3358228753Smm (void)mode; /* UNUSED */ 3359228753Smm if (set == 0 && clear == 0) 3360228753Smm return (ARCHIVE_OK); 3361228753Smm 3362228753Smm /* 3363228753Smm * XXX Is the stat here really necessary? Or can I just use 3364228753Smm * the 'set' flags directly? In particular, I'm not sure 3365228753Smm * about the correct approach if we're overwriting an existing 3366228753Smm * file that already has flags on it. XXX 3367228753Smm */ 3368231200Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 3369228753Smm return (r); 3370228753Smm 3371228753Smm a->st.st_flags &= ~clear; 3372228753Smm a->st.st_flags |= set; 3373228753Smm#ifdef HAVE_FCHFLAGS 3374228753Smm /* If platform has fchflags() and we were given an fd, use it. */ 3375228753Smm if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0) 3376228753Smm return (ARCHIVE_OK); 3377228753Smm#endif 3378228753Smm /* 3379228753Smm * If we can't use the fd to set the flags, we'll use the 3380228753Smm * pathname to set flags. We prefer lchflags() but will use 3381228753Smm * chflags() if we must. 3382228753Smm */ 3383228753Smm#ifdef HAVE_LCHFLAGS 3384228753Smm if (lchflags(name, a->st.st_flags) == 0) 3385228753Smm return (ARCHIVE_OK); 3386228753Smm#elif defined(HAVE_CHFLAGS) 3387228753Smm if (S_ISLNK(a->st.st_mode)) { 3388228753Smm archive_set_error(&a->archive, errno, 3389228753Smm "Can't set file flags on symlink."); 3390228753Smm return (ARCHIVE_WARN); 3391228753Smm } 3392228753Smm if (chflags(name, a->st.st_flags) == 0) 3393228753Smm return (ARCHIVE_OK); 3394228753Smm#endif 3395228753Smm archive_set_error(&a->archive, errno, 3396228753Smm "Failed to set file flags"); 3397228753Smm return (ARCHIVE_WARN); 3398228753Smm} 3399228753Smm 3400231200Smm#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) 3401228753Smm/* 3402228753Smm * Linux uses ioctl() to read and write file flags. 3403228753Smm */ 3404228753Smmstatic int 3405228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 3406228753Smm mode_t mode, unsigned long set, unsigned long clear) 3407228753Smm{ 3408228753Smm int ret; 3409228753Smm int myfd = fd; 3410248616Smm int newflags, oldflags; 3411248616Smm int sf_mask = 0; 3412228753Smm 3413228753Smm if (set == 0 && clear == 0) 3414228753Smm return (ARCHIVE_OK); 3415228753Smm /* Only regular files and dirs can have flags. */ 3416228753Smm if (!S_ISREG(mode) && !S_ISDIR(mode)) 3417228753Smm return (ARCHIVE_OK); 3418228753Smm 3419228753Smm /* If we weren't given an fd, open it ourselves. */ 3420248616Smm if (myfd < 0) { 3421248616Smm myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC); 3422248616Smm __archive_ensure_cloexec_flag(myfd); 3423248616Smm } 3424228753Smm if (myfd < 0) 3425228753Smm return (ARCHIVE_OK); 3426228753Smm 3427228753Smm /* 3428228753Smm * Linux has no define for the flags that are only settable by 3429228753Smm * the root user. This code may seem a little complex, but 3430228753Smm * there seem to be some Linux systems that lack these 3431228753Smm * defines. (?) The code below degrades reasonably gracefully 3432228753Smm * if sf_mask is incomplete. 3433228753Smm */ 3434228753Smm#ifdef EXT2_IMMUTABLE_FL 3435228753Smm sf_mask |= EXT2_IMMUTABLE_FL; 3436228753Smm#endif 3437228753Smm#ifdef EXT2_APPEND_FL 3438228753Smm sf_mask |= EXT2_APPEND_FL; 3439228753Smm#endif 3440228753Smm /* 3441228753Smm * XXX As above, this would be way simpler if we didn't have 3442228753Smm * to read the current flags from disk. XXX 3443228753Smm */ 3444228753Smm ret = ARCHIVE_OK; 3445231200Smm 3446231200Smm /* Read the current file flags. */ 3447231200Smm if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) < 0) 3448231200Smm goto fail; 3449231200Smm 3450228753Smm /* Try setting the flags as given. */ 3451231200Smm newflags = (oldflags & ~clear) | set; 3452231200Smm if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0) 3453231200Smm goto cleanup; 3454231200Smm if (errno != EPERM) 3455231200Smm goto fail; 3456231200Smm 3457228753Smm /* If we couldn't set all the flags, try again with a subset. */ 3458231200Smm newflags &= ~sf_mask; 3459231200Smm oldflags &= sf_mask; 3460231200Smm newflags |= oldflags; 3461231200Smm if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0) 3462231200Smm goto cleanup; 3463231200Smm 3464228753Smm /* We couldn't set the flags, so report the failure. */ 3465228753Smmfail: 3466228753Smm archive_set_error(&a->archive, errno, 3467228753Smm "Failed to set file flags"); 3468228753Smm ret = ARCHIVE_WARN; 3469228753Smmcleanup: 3470228753Smm if (fd < 0) 3471228753Smm close(myfd); 3472228753Smm return (ret); 3473228753Smm} 3474228753Smm 3475228753Smm#else 3476228753Smm 3477228753Smm/* 3478228753Smm * Of course, some systems have neither BSD chflags() nor Linux' flags 3479228753Smm * support through ioctl(). 3480228753Smm */ 3481228753Smmstatic int 3482228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 3483228753Smm mode_t mode, unsigned long set, unsigned long clear) 3484228753Smm{ 3485228753Smm (void)a; /* UNUSED */ 3486228753Smm (void)fd; /* UNUSED */ 3487228753Smm (void)name; /* UNUSED */ 3488228753Smm (void)mode; /* UNUSED */ 3489228753Smm (void)set; /* UNUSED */ 3490228753Smm (void)clear; /* UNUSED */ 3491228753Smm return (ARCHIVE_OK); 3492228753Smm} 3493228753Smm 3494228753Smm#endif /* __linux */ 3495228753Smm 3496231200Smm#ifndef HAVE_COPYFILE_H 3497231200Smm/* Default is to simply drop Mac extended metadata. */ 3498231200Smmstatic int 3499231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname, 3500231200Smm const void *metadata, size_t metadata_size) 3501231200Smm{ 3502231200Smm (void)a; /* UNUSED */ 3503231200Smm (void)pathname; /* UNUSED */ 3504231200Smm (void)metadata; /* UNUSED */ 3505231200Smm (void)metadata_size; /* UNUSED */ 3506231200Smm return (ARCHIVE_OK); 3507231200Smm} 3508248616Smm 3509248616Smmstatic int 3510248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname) 3511248616Smm{ 3512248616Smm (void)a; /* UNUSED */ 3513248616Smm (void)pathname; /* UNUSED */ 3514248616Smm return (ARCHIVE_OK); 3515248616Smm} 3516231200Smm#else 3517231200Smm 3518231200Smm/* 3519231200Smm * On Mac OS, we use copyfile() to unpack the metadata and 3520231200Smm * apply it to the target file. 3521231200Smm */ 3522248616Smm 3523248616Smm#if defined(HAVE_SYS_XATTR_H) 3524231200Smmstatic int 3525248616Smmcopy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd) 3526248616Smm{ 3527248616Smm ssize_t xattr_size; 3528248616Smm char *xattr_names = NULL, *xattr_val = NULL; 3529248616Smm int ret = ARCHIVE_OK, xattr_i; 3530248616Smm 3531248616Smm xattr_size = flistxattr(tmpfd, NULL, 0, 0); 3532248616Smm if (xattr_size == -1) { 3533248616Smm archive_set_error(&a->archive, errno, 3534248616Smm "Failed to read metadata(xattr)"); 3535248616Smm ret = ARCHIVE_WARN; 3536248616Smm goto exit_xattr; 3537248616Smm } 3538248616Smm xattr_names = malloc(xattr_size); 3539248616Smm if (xattr_names == NULL) { 3540248616Smm archive_set_error(&a->archive, ENOMEM, 3541248616Smm "Can't allocate memory for metadata(xattr)"); 3542248616Smm ret = ARCHIVE_FATAL; 3543248616Smm goto exit_xattr; 3544248616Smm } 3545248616Smm xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0); 3546248616Smm if (xattr_size == -1) { 3547248616Smm archive_set_error(&a->archive, errno, 3548248616Smm "Failed to read metadata(xattr)"); 3549248616Smm ret = ARCHIVE_WARN; 3550248616Smm goto exit_xattr; 3551248616Smm } 3552248616Smm for (xattr_i = 0; xattr_i < xattr_size; 3553248616Smm xattr_i += strlen(xattr_names + xattr_i) + 1) { 3554248616Smm ssize_t s; 3555248616Smm int f; 3556248616Smm 3557248616Smm s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0); 3558248616Smm if (s == -1) { 3559248616Smm archive_set_error(&a->archive, errno, 3560248616Smm "Failed to get metadata(xattr)"); 3561248616Smm ret = ARCHIVE_WARN; 3562248616Smm goto exit_xattr; 3563248616Smm } 3564248616Smm xattr_val = realloc(xattr_val, s); 3565248616Smm if (xattr_val == NULL) { 3566248616Smm archive_set_error(&a->archive, ENOMEM, 3567248616Smm "Failed to get metadata(xattr)"); 3568248616Smm ret = ARCHIVE_WARN; 3569248616Smm goto exit_xattr; 3570248616Smm } 3571248616Smm s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0); 3572248616Smm if (s == -1) { 3573248616Smm archive_set_error(&a->archive, errno, 3574248616Smm "Failed to get metadata(xattr)"); 3575248616Smm ret = ARCHIVE_WARN; 3576248616Smm goto exit_xattr; 3577248616Smm } 3578248616Smm f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0); 3579248616Smm if (f == -1) { 3580248616Smm archive_set_error(&a->archive, errno, 3581248616Smm "Failed to get metadata(xattr)"); 3582248616Smm ret = ARCHIVE_WARN; 3583248616Smm goto exit_xattr; 3584248616Smm } 3585248616Smm } 3586248616Smmexit_xattr: 3587248616Smm free(xattr_names); 3588248616Smm free(xattr_val); 3589248616Smm return (ret); 3590248616Smm} 3591248616Smm#endif 3592248616Smm 3593248616Smmstatic int 3594248616Smmcopy_acls(struct archive_write_disk *a, int tmpfd, int dffd) 3595248616Smm{ 3596248616Smm acl_t acl, dfacl = NULL; 3597248616Smm int acl_r, ret = ARCHIVE_OK; 3598248616Smm 3599248616Smm acl = acl_get_fd(tmpfd); 3600248616Smm if (acl == NULL) { 3601248616Smm if (errno == ENOENT) 3602248616Smm /* There are not any ACLs. */ 3603248616Smm return (ret); 3604248616Smm archive_set_error(&a->archive, errno, 3605248616Smm "Failed to get metadata(acl)"); 3606248616Smm ret = ARCHIVE_WARN; 3607248616Smm goto exit_acl; 3608248616Smm } 3609248616Smm dfacl = acl_dup(acl); 3610248616Smm acl_r = acl_set_fd(dffd, dfacl); 3611248616Smm if (acl_r == -1) { 3612248616Smm archive_set_error(&a->archive, errno, 3613248616Smm "Failed to get metadata(acl)"); 3614248616Smm ret = ARCHIVE_WARN; 3615248616Smm goto exit_acl; 3616248616Smm } 3617248616Smmexit_acl: 3618248616Smm if (acl) 3619248616Smm acl_free(acl); 3620248616Smm if (dfacl) 3621248616Smm acl_free(dfacl); 3622248616Smm return (ret); 3623248616Smm} 3624248616Smm 3625248616Smmstatic int 3626248616Smmcreate_tempdatafork(struct archive_write_disk *a, const char *pathname) 3627248616Smm{ 3628248616Smm struct archive_string tmpdatafork; 3629248616Smm int tmpfd; 3630248616Smm 3631248616Smm archive_string_init(&tmpdatafork); 3632248616Smm archive_strcpy(&tmpdatafork, "tar.md.XXXXXX"); 3633248616Smm tmpfd = mkstemp(tmpdatafork.s); 3634248616Smm if (tmpfd < 0) { 3635248616Smm archive_set_error(&a->archive, errno, 3636248616Smm "Failed to mkstemp"); 3637248616Smm archive_string_free(&tmpdatafork); 3638248616Smm return (-1); 3639248616Smm } 3640248616Smm if (copyfile(pathname, tmpdatafork.s, 0, 3641248616Smm COPYFILE_UNPACK | COPYFILE_NOFOLLOW 3642248616Smm | COPYFILE_ACL | COPYFILE_XATTR) < 0) { 3643248616Smm archive_set_error(&a->archive, errno, 3644248616Smm "Failed to restore metadata"); 3645248616Smm close(tmpfd); 3646248616Smm tmpfd = -1; 3647248616Smm } 3648248616Smm unlink(tmpdatafork.s); 3649248616Smm archive_string_free(&tmpdatafork); 3650248616Smm return (tmpfd); 3651248616Smm} 3652248616Smm 3653248616Smmstatic int 3654248616Smmcopy_metadata(struct archive_write_disk *a, const char *metadata, 3655248616Smm const char *datafork, int datafork_compressed) 3656248616Smm{ 3657248616Smm int ret = ARCHIVE_OK; 3658248616Smm 3659248616Smm if (datafork_compressed) { 3660248616Smm int dffd, tmpfd; 3661248616Smm 3662248616Smm tmpfd = create_tempdatafork(a, metadata); 3663248616Smm if (tmpfd == -1) 3664248616Smm return (ARCHIVE_WARN); 3665248616Smm 3666248616Smm /* 3667248616Smm * Do not open the data fork compressed by HFS+ compression 3668248616Smm * with at least a writing mode(O_RDWR or O_WRONLY). it 3669248616Smm * makes the data fork uncompressed. 3670248616Smm */ 3671248616Smm dffd = open(datafork, 0); 3672248616Smm if (dffd == -1) { 3673248616Smm archive_set_error(&a->archive, errno, 3674248616Smm "Failed to open the data fork for metadata"); 3675248616Smm close(tmpfd); 3676248616Smm return (ARCHIVE_WARN); 3677248616Smm } 3678248616Smm 3679248616Smm#if defined(HAVE_SYS_XATTR_H) 3680248616Smm ret = copy_xattrs(a, tmpfd, dffd); 3681248616Smm if (ret == ARCHIVE_OK) 3682248616Smm#endif 3683248616Smm ret = copy_acls(a, tmpfd, dffd); 3684248616Smm close(tmpfd); 3685248616Smm close(dffd); 3686248616Smm } else { 3687248616Smm if (copyfile(metadata, datafork, 0, 3688248616Smm COPYFILE_UNPACK | COPYFILE_NOFOLLOW 3689248616Smm | COPYFILE_ACL | COPYFILE_XATTR) < 0) { 3690248616Smm archive_set_error(&a->archive, errno, 3691248616Smm "Failed to restore metadata"); 3692248616Smm ret = ARCHIVE_WARN; 3693248616Smm } 3694248616Smm } 3695248616Smm return (ret); 3696248616Smm} 3697248616Smm 3698248616Smmstatic int 3699231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname, 3700231200Smm const void *metadata, size_t metadata_size) 3701231200Smm{ 3702231200Smm struct archive_string tmp; 3703231200Smm ssize_t written; 3704231200Smm int fd; 3705231200Smm int ret = ARCHIVE_OK; 3706231200Smm 3707231200Smm /* This would be simpler if copyfile() could just accept the 3708231200Smm * metadata as a block of memory; then we could sidestep this 3709231200Smm * silly dance of writing the data to disk just so that 3710231200Smm * copyfile() can read it back in again. */ 3711231200Smm archive_string_init(&tmp); 3712231200Smm archive_strcpy(&tmp, pathname); 3713231200Smm archive_strcat(&tmp, ".XXXXXX"); 3714231200Smm fd = mkstemp(tmp.s); 3715231200Smm 3716231200Smm if (fd < 0) { 3717231200Smm archive_set_error(&a->archive, errno, 3718231200Smm "Failed to restore metadata"); 3719248616Smm archive_string_free(&tmp); 3720231200Smm return (ARCHIVE_WARN); 3721231200Smm } 3722231200Smm written = write(fd, metadata, metadata_size); 3723231200Smm close(fd); 3724248616Smm if ((size_t)written != metadata_size) { 3725231200Smm archive_set_error(&a->archive, errno, 3726231200Smm "Failed to restore metadata"); 3727231200Smm ret = ARCHIVE_WARN; 3728248616Smm } else { 3729248616Smm int compressed; 3730248616Smm 3731248616Smm#if defined(UF_COMPRESSED) 3732248616Smm if ((a->todo & TODO_HFS_COMPRESSION) != 0 && 3733248616Smm (ret = lazy_stat(a)) == ARCHIVE_OK) 3734248616Smm compressed = a->st.st_flags & UF_COMPRESSED; 3735248616Smm else 3736248616Smm#endif 3737248616Smm compressed = 0; 3738248616Smm ret = copy_metadata(a, tmp.s, pathname, compressed); 3739231200Smm } 3740231200Smm unlink(tmp.s); 3741248616Smm archive_string_free(&tmp); 3742231200Smm return (ret); 3743231200Smm} 3744248616Smm 3745248616Smmstatic int 3746248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname) 3747248616Smm{ 3748248616Smm char buff[8]; 3749248616Smm struct stat st; 3750248616Smm const char *p; 3751248616Smm struct archive_string datafork; 3752248616Smm int fd = -1, ret = ARCHIVE_OK; 3753248616Smm 3754248616Smm archive_string_init(&datafork); 3755248616Smm /* Check if the current file name is a type of the resource 3756248616Smm * fork file. */ 3757248616Smm p = strrchr(pathname, '/'); 3758248616Smm if (p == NULL) 3759248616Smm p = pathname; 3760248616Smm else 3761248616Smm p++; 3762248616Smm if (p[0] != '.' || p[1] != '_') 3763248616Smm goto skip_appledouble; 3764248616Smm 3765248616Smm /* 3766248616Smm * Check if the data fork file exists. 3767248616Smm * 3768248616Smm * TODO: Check if this write disk object has handled it. 3769248616Smm */ 3770248616Smm archive_strncpy(&datafork, pathname, p - pathname); 3771248616Smm archive_strcat(&datafork, p + 2); 3772248616Smm if (lstat(datafork.s, &st) == -1 || 3773248616Smm (st.st_mode & AE_IFMT) != AE_IFREG) 3774248616Smm goto skip_appledouble; 3775248616Smm 3776248616Smm /* 3777248616Smm * Check if the file is in the AppleDouble form. 3778248616Smm */ 3779248616Smm fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC); 3780248616Smm __archive_ensure_cloexec_flag(fd); 3781248616Smm if (fd == -1) { 3782248616Smm archive_set_error(&a->archive, errno, 3783248616Smm "Failed to open a restoring file"); 3784248616Smm ret = ARCHIVE_WARN; 3785248616Smm goto skip_appledouble; 3786248616Smm } 3787248616Smm if (read(fd, buff, 8) == -1) { 3788248616Smm archive_set_error(&a->archive, errno, 3789248616Smm "Failed to read a restoring file"); 3790248616Smm close(fd); 3791248616Smm ret = ARCHIVE_WARN; 3792248616Smm goto skip_appledouble; 3793248616Smm } 3794248616Smm close(fd); 3795248616Smm /* Check AppleDouble Magic Code. */ 3796248616Smm if (archive_be32dec(buff) != 0x00051607) 3797248616Smm goto skip_appledouble; 3798248616Smm /* Check AppleDouble Version. */ 3799248616Smm if (archive_be32dec(buff+4) != 0x00020000) 3800248616Smm goto skip_appledouble; 3801248616Smm 3802248616Smm ret = copy_metadata(a, pathname, datafork.s, 3803248616Smm#if defined(UF_COMPRESSED) 3804248616Smm st.st_flags & UF_COMPRESSED); 3805248616Smm#else 3806248616Smm 0); 3807231200Smm#endif 3808248616Smm if (ret == ARCHIVE_OK) { 3809248616Smm unlink(pathname); 3810248616Smm ret = ARCHIVE_EOF; 3811248616Smm } 3812248616Smmskip_appledouble: 3813248616Smm archive_string_free(&datafork); 3814248616Smm return (ret); 3815248616Smm} 3816248616Smm#endif 3817231200Smm 3818231200Smm#if HAVE_LSETXATTR || HAVE_LSETEA 3819228753Smm/* 3820231200Smm * Restore extended attributes - Linux and AIX implementations: 3821231200Smm * AIX' ea interface is syntaxwise identical to the Linux xattr interface. 3822228753Smm */ 3823228753Smmstatic int 3824228753Smmset_xattrs(struct archive_write_disk *a) 3825228753Smm{ 3826228753Smm struct archive_entry *entry = a->entry; 3827228753Smm static int warning_done = 0; 3828228753Smm int ret = ARCHIVE_OK; 3829228753Smm int i = archive_entry_xattr_reset(entry); 3830228753Smm 3831228753Smm while (i--) { 3832228753Smm const char *name; 3833228753Smm const void *value; 3834228753Smm size_t size; 3835228753Smm archive_entry_xattr_next(entry, &name, &value, &size); 3836228753Smm if (name != NULL && 3837228753Smm strncmp(name, "xfsroot.", 8) != 0 && 3838228753Smm strncmp(name, "system.", 7) != 0) { 3839228753Smm int e; 3840228753Smm#if HAVE_FSETXATTR 3841228753Smm if (a->fd >= 0) 3842228753Smm e = fsetxattr(a->fd, name, value, size, 0); 3843228753Smm else 3844231200Smm#elif HAVE_FSETEA 3845231200Smm if (a->fd >= 0) 3846231200Smm e = fsetea(a->fd, name, value, size, 0); 3847231200Smm else 3848228753Smm#endif 3849228753Smm { 3850231200Smm#if HAVE_LSETXATTR 3851228753Smm e = lsetxattr(archive_entry_pathname(entry), 3852228753Smm name, value, size, 0); 3853231200Smm#elif HAVE_LSETEA 3854231200Smm e = lsetea(archive_entry_pathname(entry), 3855231200Smm name, value, size, 0); 3856231200Smm#endif 3857228753Smm } 3858228753Smm if (e == -1) { 3859231200Smm if (errno == ENOTSUP || errno == ENOSYS) { 3860228753Smm if (!warning_done) { 3861228753Smm warning_done = 1; 3862228753Smm archive_set_error(&a->archive, errno, 3863228753Smm "Cannot restore extended " 3864228753Smm "attributes on this file " 3865228753Smm "system"); 3866228753Smm } 3867228753Smm } else 3868228753Smm archive_set_error(&a->archive, errno, 3869228753Smm "Failed to set extended attribute"); 3870228753Smm ret = ARCHIVE_WARN; 3871228753Smm } 3872228753Smm } else { 3873228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 3874228753Smm "Invalid extended attribute encountered"); 3875228753Smm ret = ARCHIVE_WARN; 3876228753Smm } 3877228753Smm } 3878228753Smm return (ret); 3879228753Smm} 3880228753Smm#elif HAVE_EXTATTR_SET_FILE && HAVE_DECL_EXTATTR_NAMESPACE_USER 3881228753Smm/* 3882228753Smm * Restore extended attributes - FreeBSD implementation 3883228753Smm */ 3884228753Smmstatic int 3885228753Smmset_xattrs(struct archive_write_disk *a) 3886228753Smm{ 3887228753Smm struct archive_entry *entry = a->entry; 3888228753Smm static int warning_done = 0; 3889228753Smm int ret = ARCHIVE_OK; 3890228753Smm int i = archive_entry_xattr_reset(entry); 3891228753Smm 3892228753Smm while (i--) { 3893228753Smm const char *name; 3894228753Smm const void *value; 3895228753Smm size_t size; 3896228753Smm archive_entry_xattr_next(entry, &name, &value, &size); 3897228753Smm if (name != NULL) { 3898248995Smdf ssize_t e; 3899228753Smm int namespace; 3900228753Smm 3901228753Smm if (strncmp(name, "user.", 5) == 0) { 3902228753Smm /* "user." attributes go to user namespace */ 3903228753Smm name += 5; 3904228753Smm namespace = EXTATTR_NAMESPACE_USER; 3905228753Smm } else { 3906228753Smm /* Warn about other extended attributes. */ 3907228753Smm archive_set_error(&a->archive, 3908228753Smm ARCHIVE_ERRNO_FILE_FORMAT, 3909228753Smm "Can't restore extended attribute ``%s''", 3910228753Smm name); 3911228753Smm ret = ARCHIVE_WARN; 3912228753Smm continue; 3913228753Smm } 3914228753Smm errno = 0; 3915228753Smm#if HAVE_EXTATTR_SET_FD 3916228753Smm if (a->fd >= 0) 3917228753Smm e = extattr_set_fd(a->fd, namespace, name, value, size); 3918228753Smm else 3919228753Smm#endif 3920228753Smm /* TODO: should we use extattr_set_link() instead? */ 3921228753Smm { 3922228753Smm e = extattr_set_file(archive_entry_pathname(entry), 3923228753Smm namespace, name, value, size); 3924228753Smm } 3925248995Smdf if (e != (ssize_t)size) { 3926231200Smm if (errno == ENOTSUP || errno == ENOSYS) { 3927228753Smm if (!warning_done) { 3928228753Smm warning_done = 1; 3929228753Smm archive_set_error(&a->archive, errno, 3930228753Smm "Cannot restore extended " 3931228753Smm "attributes on this file " 3932228753Smm "system"); 3933228753Smm } 3934228753Smm } else { 3935228753Smm archive_set_error(&a->archive, errno, 3936228753Smm "Failed to set extended attribute"); 3937228753Smm } 3938228753Smm 3939228753Smm ret = ARCHIVE_WARN; 3940228753Smm } 3941228753Smm } 3942228753Smm } 3943228753Smm return (ret); 3944228753Smm} 3945228753Smm#else 3946228753Smm/* 3947228753Smm * Restore extended attributes - stub implementation for unsupported systems 3948228753Smm */ 3949228753Smmstatic int 3950228753Smmset_xattrs(struct archive_write_disk *a) 3951228753Smm{ 3952228753Smm static int warning_done = 0; 3953228753Smm 3954228753Smm /* If there aren't any extended attributes, then it's okay not 3955228753Smm * to extract them, otherwise, issue a single warning. */ 3956228753Smm if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) { 3957228753Smm warning_done = 1; 3958228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 3959228753Smm "Cannot restore extended attributes on this system"); 3960228753Smm return (ARCHIVE_WARN); 3961228753Smm } 3962228753Smm /* Warning was already emitted; suppress further warnings. */ 3963228753Smm return (ARCHIVE_OK); 3964228753Smm} 3965228753Smm#endif 3966228753Smm 3967228753Smm/* 3968228753Smm * Test if file on disk is older than entry. 3969228753Smm */ 3970228753Smmstatic int 3971228753Smmolder(struct stat *st, struct archive_entry *entry) 3972228753Smm{ 3973228753Smm /* First, test the seconds and return if we have a definite answer. */ 3974228753Smm /* Definitely older. */ 3975228753Smm if (st->st_mtime < archive_entry_mtime(entry)) 3976228753Smm return (1); 3977228753Smm /* Definitely younger. */ 3978228753Smm if (st->st_mtime > archive_entry_mtime(entry)) 3979228753Smm return (0); 3980228753Smm /* If this platform supports fractional seconds, try those. */ 3981228753Smm#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 3982228753Smm /* Definitely older. */ 3983228753Smm if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry)) 3984228753Smm return (1); 3985228753Smm#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 3986228753Smm /* Definitely older. */ 3987228753Smm if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry)) 3988228753Smm return (1); 3989228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_N 3990228753Smm /* older. */ 3991228753Smm if (st->st_mtime_n < archive_entry_mtime_nsec(entry)) 3992228753Smm return (1); 3993228753Smm#elif HAVE_STRUCT_STAT_ST_UMTIME 3994228753Smm /* older. */ 3995228753Smm if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry)) 3996228753Smm return (1); 3997228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_USEC 3998228753Smm /* older. */ 3999228753Smm if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry)) 4000228753Smm return (1); 4001228753Smm#else 4002228753Smm /* This system doesn't have high-res timestamps. */ 4003228753Smm#endif 4004228753Smm /* Same age or newer, so not older. */ 4005228753Smm return (0); 4006228753Smm} 4007231200Smm 4008231200Smm#endif /* !_WIN32 || __CYGWIN__ */ 4009231200Smm 4010