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 143248616Smm#define O_CLOEXEC 0 144248616Smm#endif 145228753Smm 146228753Smmstruct fixup_entry { 147228753Smm struct fixup_entry *next; 148231200Smm struct archive_acl acl; 149228753Smm mode_t mode; 150228753Smm int64_t atime; 151228753Smm int64_t birthtime; 152228753Smm int64_t mtime; 153231200Smm int64_t ctime; 154228753Smm unsigned long atime_nanos; 155228753Smm unsigned long birthtime_nanos; 156228753Smm unsigned long mtime_nanos; 157231200Smm unsigned long ctime_nanos; 158228753Smm unsigned long fflags_set; 159231200Smm size_t mac_metadata_size; 160231200Smm void *mac_metadata; 161228753Smm int fixup; /* bitmask of what needs fixing */ 162228753Smm char *name; 163228753Smm}; 164228753Smm 165228753Smm/* 166228753Smm * We use a bitmask to track which operations remain to be done for 167228753Smm * this file. In particular, this helps us avoid unnecessary 168228753Smm * operations when it's possible to take care of one step as a 169228753Smm * side-effect of another. For example, mkdir() can specify the mode 170228753Smm * for the newly-created object but symlink() cannot. This means we 171228753Smm * can skip chmod() if mkdir() succeeded, but we must explicitly 172228753Smm * chmod() if we're trying to create a directory that already exists 173228753Smm * (mkdir() failed) or if we're restoring a symlink. Similarly, we 174228753Smm * need to verify UID/GID before trying to restore SUID/SGID bits; 175228753Smm * that verification can occur explicitly through a stat() call or 176228753Smm * implicitly because of a successful chown() call. 177228753Smm */ 178228753Smm#define TODO_MODE_FORCE 0x40000000 179228753Smm#define TODO_MODE_BASE 0x20000000 180228753Smm#define TODO_SUID 0x10000000 181228753Smm#define TODO_SUID_CHECK 0x08000000 182228753Smm#define TODO_SGID 0x04000000 183228753Smm#define TODO_SGID_CHECK 0x02000000 184248616Smm#define TODO_APPLEDOUBLE 0x01000000 185228753Smm#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID) 186228753Smm#define TODO_TIMES ARCHIVE_EXTRACT_TIME 187228753Smm#define TODO_OWNER ARCHIVE_EXTRACT_OWNER 188228753Smm#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS 189228753Smm#define TODO_ACLS ARCHIVE_EXTRACT_ACL 190228753Smm#define TODO_XATTR ARCHIVE_EXTRACT_XATTR 191231200Smm#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA 192248616Smm#define TODO_HFS_COMPRESSION ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED 193228753Smm 194228753Smmstruct archive_write_disk { 195228753Smm struct archive archive; 196228753Smm 197228753Smm mode_t user_umask; 198228753Smm struct fixup_entry *fixup_list; 199228753Smm struct fixup_entry *current_fixup; 200231200Smm int64_t user_uid; 201231200Smm int skip_file_set; 202238856Smm int64_t skip_file_dev; 203238856Smm int64_t skip_file_ino; 204228753Smm time_t start_time; 205228753Smm 206231200Smm int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid); 207228753Smm void (*cleanup_gid)(void *private); 208228753Smm void *lookup_gid_data; 209231200Smm int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid); 210228753Smm void (*cleanup_uid)(void *private); 211228753Smm void *lookup_uid_data; 212228753Smm 213228753Smm /* 214228753Smm * Full path of last file to satisfy symlink checks. 215228753Smm */ 216228753Smm struct archive_string path_safe; 217228753Smm 218228753Smm /* 219228753Smm * Cached stat data from disk for the current entry. 220228753Smm * If this is valid, pst points to st. Otherwise, 221228753Smm * pst is null. 222228753Smm */ 223228753Smm struct stat st; 224228753Smm struct stat *pst; 225228753Smm 226228753Smm /* Information about the object being restored right now. */ 227228753Smm struct archive_entry *entry; /* Entry being extracted. */ 228228753Smm char *name; /* Name of entry, possibly edited. */ 229228753Smm struct archive_string _name_data; /* backing store for 'name' */ 230228753Smm /* Tasks remaining for this object. */ 231228753Smm int todo; 232228753Smm /* Tasks deferred until end-of-archive. */ 233228753Smm int deferred; 234228753Smm /* Options requested by the client. */ 235228753Smm int flags; 236228753Smm /* Handle for the file we're restoring. */ 237228753Smm int fd; 238228753Smm /* Current offset for writing data to the file. */ 239231200Smm int64_t offset; 240228753Smm /* Last offset actually written to disk. */ 241231200Smm int64_t fd_offset; 242231200Smm /* Total bytes actually written to files. */ 243231200Smm int64_t total_bytes_written; 244228753Smm /* Maximum size of file, -1 if unknown. */ 245231200Smm int64_t filesize; 246228753Smm /* Dir we were in before this restore; only for deep paths. */ 247228753Smm int restore_pwd; 248228753Smm /* Mode we should use for this entry; affected by _PERM and umask. */ 249228753Smm mode_t mode; 250228753Smm /* UID/GID to use in restoring this entry. */ 251231200Smm int64_t uid; 252231200Smm int64_t gid; 253248616Smm /* 254248616Smm * HFS+ Compression. 255248616Smm */ 256248616Smm /* Xattr "com.apple.decmpfs". */ 257248616Smm uint32_t decmpfs_attr_size; 258248616Smm unsigned char *decmpfs_header_p; 259248616Smm /* ResourceFork set options used for fsetxattr. */ 260248616Smm int rsrc_xattr_options; 261248616Smm /* Xattr "com.apple.ResourceFork". */ 262248616Smm unsigned char *resource_fork; 263248616Smm size_t resource_fork_allocated_size; 264248616Smm unsigned int decmpfs_block_count; 265248616Smm uint32_t *decmpfs_block_info; 266248616Smm /* Buffer for compressed data. */ 267248616Smm unsigned char *compressed_buffer; 268248616Smm size_t compressed_buffer_size; 269248616Smm size_t compressed_buffer_remaining; 270248616Smm /* The offset of the ResourceFork where compressed data will 271248616Smm * be placed. */ 272248616Smm uint32_t compressed_rsrc_position; 273248616Smm uint32_t compressed_rsrc_position_v; 274248616Smm /* Buffer for uncompressed data. */ 275248616Smm char *uncompressed_buffer; 276248616Smm size_t block_remaining_bytes; 277248616Smm size_t file_remaining_bytes; 278248616Smm#ifdef HAVE_ZLIB_H 279248616Smm z_stream stream; 280248616Smm int stream_valid; 281248616Smm int decmpfs_compression_level; 282248616Smm#endif 283228753Smm}; 284228753Smm 285228753Smm/* 286228753Smm * Default mode for dirs created automatically (will be modified by umask). 287231200Smm * Note that POSIX specifies 0777 for implicitly-created dirs, "modified 288228753Smm * by the process' file creation mask." 289228753Smm */ 290228753Smm#define DEFAULT_DIR_MODE 0777 291228753Smm/* 292228753Smm * Dir modes are restored in two steps: During the extraction, the permissions 293228753Smm * in the archive are modified to match the following limits. During 294228753Smm * the post-extract fixup pass, the permissions from the archive are 295228753Smm * applied. 296228753Smm */ 297228753Smm#define MINIMUM_DIR_MODE 0700 298228753Smm#define MAXIMUM_DIR_MODE 0775 299228753Smm 300248616Smm/* 301248616Smm * Maxinum uncompressed size of a decmpfs block. 302248616Smm */ 303248616Smm#define MAX_DECMPFS_BLOCK_SIZE (64 * 1024) 304248616Smm/* 305248616Smm * HFS+ compression type. 306248616Smm */ 307248616Smm#define CMP_XATTR 3/* Compressed data in xattr. */ 308248616Smm#define CMP_RESOURCE_FORK 4/* Compressed data in resource fork. */ 309248616Smm/* 310248616Smm * HFS+ compression resource fork. 311248616Smm */ 312248616Smm#define RSRC_H_SIZE 260 /* Base size of Resource fork header. */ 313248616Smm#define RSRC_F_SIZE 50 /* Size of Resource fork footer. */ 314248616Smm/* Size to write compressed data to resource fork. */ 315248616Smm#define COMPRESSED_W_SIZE (64 * 1024) 316248616Smm/* decmpfs difinitions. */ 317248616Smm#define MAX_DECMPFS_XATTR_SIZE 3802 318248616Smm#ifndef DECMPFS_XATTR_NAME 319248616Smm#define DECMPFS_XATTR_NAME "com.apple.decmpfs" 320248616Smm#endif 321248616Smm#define DECMPFS_MAGIC 0x636d7066 322248616Smm#define DECMPFS_COMPRESSION_MAGIC 0 323248616Smm#define DECMPFS_COMPRESSION_TYPE 4 324248616Smm#define DECMPFS_UNCOMPRESSED_SIZE 8 325248616Smm#define DECMPFS_HEADER_SIZE 16 326248616Smm 327248616Smm#define HFS_BLOCKS(s) ((s) >> 12) 328248616Smm 329228753Smmstatic int check_symlinks(struct archive_write_disk *); 330228753Smmstatic int create_filesystem_object(struct archive_write_disk *); 331228753Smmstatic struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname); 332231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX) 333228753Smmstatic void edit_deep_directories(struct archive_write_disk *ad); 334228753Smm#endif 335228753Smmstatic int cleanup_pathname(struct archive_write_disk *); 336228753Smmstatic int create_dir(struct archive_write_disk *, char *); 337228753Smmstatic int create_parent_dir(struct archive_write_disk *, char *); 338248616Smmstatic ssize_t hfs_write_data_block(struct archive_write_disk *, 339248616Smm const char *, size_t); 340248616Smmstatic int fixup_appledouble(struct archive_write_disk *, const char *); 341228753Smmstatic int older(struct stat *, struct archive_entry *); 342228753Smmstatic int restore_entry(struct archive_write_disk *); 343231200Smmstatic int set_mac_metadata(struct archive_write_disk *, const char *, 344231200Smm const void *, size_t); 345228753Smmstatic int set_xattrs(struct archive_write_disk *); 346228753Smmstatic int set_fflags(struct archive_write_disk *); 347228753Smmstatic int set_fflags_platform(struct archive_write_disk *, int fd, 348228753Smm const char *name, mode_t mode, 349228753Smm unsigned long fflags_set, unsigned long fflags_clear); 350228753Smmstatic int set_ownership(struct archive_write_disk *); 351228753Smmstatic int set_mode(struct archive_write_disk *, int mode); 352228753Smmstatic int set_time(int, int, const char *, time_t, long, time_t, long); 353231200Smmstatic int set_times(struct archive_write_disk *, int, int, const char *, 354231200Smm time_t, long, time_t, long, time_t, long, time_t, long); 355231200Smmstatic int set_times_from_entry(struct archive_write_disk *); 356228753Smmstatic struct fixup_entry *sort_dir_list(struct fixup_entry *p); 357228753Smmstatic ssize_t write_data_block(struct archive_write_disk *, 358228753Smm const char *, size_t); 359228753Smm 360228753Smmstatic struct archive_vtable *archive_write_disk_vtable(void); 361228753Smm 362231200Smmstatic int _archive_write_disk_close(struct archive *); 363231200Smmstatic int _archive_write_disk_free(struct archive *); 364231200Smmstatic int _archive_write_disk_header(struct archive *, struct archive_entry *); 365231200Smmstatic int64_t _archive_write_disk_filter_bytes(struct archive *, int); 366231200Smmstatic int _archive_write_disk_finish_entry(struct archive *); 367231200Smmstatic ssize_t _archive_write_disk_data(struct archive *, const void *, size_t); 368231200Smmstatic ssize_t _archive_write_disk_data_block(struct archive *, const void *, size_t, int64_t); 369228753Smm 370228753Smmstatic int 371231200Smmlazy_stat(struct archive_write_disk *a) 372228753Smm{ 373228753Smm if (a->pst != NULL) { 374228753Smm /* Already have stat() data available. */ 375228753Smm return (ARCHIVE_OK); 376228753Smm } 377228753Smm#ifdef HAVE_FSTAT 378228753Smm if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) { 379228753Smm a->pst = &a->st; 380228753Smm return (ARCHIVE_OK); 381228753Smm } 382228753Smm#endif 383228753Smm /* 384228753Smm * XXX At this point, symlinks should not be hit, otherwise 385231200Smm * XXX a race occurred. Do we want to check explicitly for that? 386228753Smm */ 387228753Smm if (lstat(a->name, &a->st) == 0) { 388228753Smm a->pst = &a->st; 389228753Smm return (ARCHIVE_OK); 390228753Smm } 391228753Smm archive_set_error(&a->archive, errno, "Couldn't stat file"); 392228753Smm return (ARCHIVE_WARN); 393228753Smm} 394228753Smm 395228753Smmstatic struct archive_vtable * 396228753Smmarchive_write_disk_vtable(void) 397228753Smm{ 398228753Smm static struct archive_vtable av; 399228753Smm static int inited = 0; 400228753Smm 401228753Smm if (!inited) { 402231200Smm av.archive_close = _archive_write_disk_close; 403231200Smm av.archive_filter_bytes = _archive_write_disk_filter_bytes; 404231200Smm av.archive_free = _archive_write_disk_free; 405231200Smm av.archive_write_header = _archive_write_disk_header; 406231200Smm av.archive_write_finish_entry 407231200Smm = _archive_write_disk_finish_entry; 408231200Smm av.archive_write_data = _archive_write_disk_data; 409231200Smm av.archive_write_data_block = _archive_write_disk_data_block; 410231200Smm inited = 1; 411228753Smm } 412228753Smm return (&av); 413228753Smm} 414228753Smm 415231200Smmstatic int64_t 416231200Smm_archive_write_disk_filter_bytes(struct archive *_a, int n) 417231200Smm{ 418231200Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 419231200Smm (void)n; /* UNUSED */ 420231200Smm if (n == -1 || n == 0) 421231200Smm return (a->total_bytes_written); 422231200Smm return (-1); 423231200Smm} 424228753Smm 425231200Smm 426228753Smmint 427228753Smmarchive_write_disk_set_options(struct archive *_a, int flags) 428228753Smm{ 429228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 430228753Smm 431228753Smm a->flags = flags; 432228753Smm return (ARCHIVE_OK); 433228753Smm} 434228753Smm 435228753Smm 436228753Smm/* 437228753Smm * Extract this entry to disk. 438228753Smm * 439228753Smm * TODO: Validate hardlinks. According to the standards, we're 440228753Smm * supposed to check each extracted hardlink and squawk if it refers 441228753Smm * to a file that we didn't restore. I'm not entirely convinced this 442228753Smm * is a good idea, but more importantly: Is there any way to validate 443228753Smm * hardlinks without keeping a complete list of filenames from the 444228753Smm * entire archive?? Ugh. 445228753Smm * 446228753Smm */ 447228753Smmstatic int 448231200Smm_archive_write_disk_header(struct archive *_a, struct archive_entry *entry) 449228753Smm{ 450228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 451228753Smm struct fixup_entry *fe; 452228753Smm int ret, r; 453228753Smm 454231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 455228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 456228753Smm "archive_write_disk_header"); 457228753Smm archive_clear_error(&a->archive); 458228753Smm if (a->archive.state & ARCHIVE_STATE_DATA) { 459231200Smm r = _archive_write_disk_finish_entry(&a->archive); 460228753Smm if (r == ARCHIVE_FATAL) 461228753Smm return (r); 462228753Smm } 463228753Smm 464228753Smm /* Set up for this particular entry. */ 465228753Smm a->pst = NULL; 466228753Smm a->current_fixup = NULL; 467228753Smm a->deferred = 0; 468228753Smm if (a->entry) { 469228753Smm archive_entry_free(a->entry); 470228753Smm a->entry = NULL; 471228753Smm } 472228753Smm a->entry = archive_entry_clone(entry); 473228753Smm a->fd = -1; 474228753Smm a->fd_offset = 0; 475228753Smm a->offset = 0; 476231200Smm a->restore_pwd = -1; 477228753Smm a->uid = a->user_uid; 478228753Smm a->mode = archive_entry_mode(a->entry); 479228753Smm if (archive_entry_size_is_set(a->entry)) 480228753Smm a->filesize = archive_entry_size(a->entry); 481228753Smm else 482228753Smm a->filesize = -1; 483228753Smm archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry)); 484228753Smm a->name = a->_name_data.s; 485228753Smm archive_clear_error(&a->archive); 486228753Smm 487228753Smm /* 488228753Smm * Clean up the requested path. This is necessary for correct 489228753Smm * dir restores; the dir restore logic otherwise gets messed 490228753Smm * up by nonsense like "dir/.". 491228753Smm */ 492228753Smm ret = cleanup_pathname(a); 493228753Smm if (ret != ARCHIVE_OK) 494228753Smm return (ret); 495228753Smm 496228753Smm /* 497231200Smm * Query the umask so we get predictable mode settings. 498228753Smm * This gets done on every call to _write_header in case the 499228753Smm * user edits their umask during the extraction for some 500231200Smm * reason. 501228753Smm */ 502231200Smm umask(a->user_umask = umask(0)); 503228753Smm 504228753Smm /* Figure out what we need to do for this entry. */ 505228753Smm a->todo = TODO_MODE_BASE; 506228753Smm if (a->flags & ARCHIVE_EXTRACT_PERM) { 507228753Smm a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ 508228753Smm /* 509228753Smm * SGID requires an extra "check" step because we 510228753Smm * cannot easily predict the GID that the system will 511228753Smm * assign. (Different systems assign GIDs to files 512228753Smm * based on a variety of criteria, including process 513228753Smm * credentials and the gid of the enclosing 514228753Smm * directory.) We can only restore the SGID bit if 515228753Smm * the file has the right GID, and we only know the 516228753Smm * GID if we either set it (see set_ownership) or if 517228753Smm * we've actually called stat() on the file after it 518228753Smm * was restored. Since there are several places at 519228753Smm * which we might verify the GID, we need a TODO bit 520228753Smm * to keep track. 521228753Smm */ 522228753Smm if (a->mode & S_ISGID) 523228753Smm a->todo |= TODO_SGID | TODO_SGID_CHECK; 524228753Smm /* 525228753Smm * Verifying the SUID is simpler, but can still be 526228753Smm * done in multiple ways, hence the separate "check" bit. 527228753Smm */ 528228753Smm if (a->mode & S_ISUID) 529228753Smm a->todo |= TODO_SUID | TODO_SUID_CHECK; 530228753Smm } else { 531228753Smm /* 532228753Smm * User didn't request full permissions, so don't 533228753Smm * restore SUID, SGID bits and obey umask. 534228753Smm */ 535228753Smm a->mode &= ~S_ISUID; 536228753Smm a->mode &= ~S_ISGID; 537228753Smm a->mode &= ~S_ISVTX; 538228753Smm a->mode &= ~a->user_umask; 539228753Smm } 540228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) 541228753Smm a->todo |= TODO_OWNER; 542228753Smm if (a->flags & ARCHIVE_EXTRACT_TIME) 543228753Smm a->todo |= TODO_TIMES; 544231200Smm if (a->flags & ARCHIVE_EXTRACT_ACL) { 545231200Smm if (archive_entry_filetype(a->entry) == AE_IFDIR) 546231200Smm a->deferred |= TODO_ACLS; 547231200Smm else 548231200Smm a->todo |= TODO_ACLS; 549231200Smm } 550231200Smm if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) { 551231200Smm if (archive_entry_filetype(a->entry) == AE_IFDIR) 552231200Smm a->deferred |= TODO_MAC_METADATA; 553231200Smm else 554231200Smm a->todo |= TODO_MAC_METADATA; 555231200Smm } 556248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) 557248616Smm if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) { 558248616Smm unsigned long set, clear; 559248616Smm archive_entry_fflags(a->entry, &set, &clear); 560248616Smm if ((set & ~clear) & UF_COMPRESSED) { 561248616Smm a->todo |= TODO_HFS_COMPRESSION; 562248616Smm a->decmpfs_block_count = (unsigned)-1; 563248616Smm } 564248616Smm } 565248616Smm if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 && 566248616Smm (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) { 567248616Smm a->todo |= TODO_HFS_COMPRESSION; 568248616Smm a->decmpfs_block_count = (unsigned)-1; 569248616Smm } 570248616Smm { 571248616Smm const char *p; 572248616Smm 573248616Smm /* Check if the current file name is a type of the 574248616Smm * resource fork file. */ 575248616Smm p = strrchr(a->name, '/'); 576248616Smm if (p == NULL) 577248616Smm p = a->name; 578248616Smm else 579248616Smm p++; 580248616Smm if (p[0] == '.' && p[1] == '_') { 581248616Smm /* Do not compress "._XXX" files. */ 582248616Smm a->todo &= ~TODO_HFS_COMPRESSION; 583248616Smm if (a->filesize > 0) 584248616Smm a->todo |= TODO_APPLEDOUBLE; 585248616Smm } 586248616Smm } 587248616Smm#endif 588248616Smm 589228753Smm if (a->flags & ARCHIVE_EXTRACT_XATTR) 590228753Smm a->todo |= TODO_XATTR; 591228753Smm if (a->flags & ARCHIVE_EXTRACT_FFLAGS) 592228753Smm a->todo |= TODO_FFLAGS; 593228753Smm if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { 594228753Smm ret = check_symlinks(a); 595228753Smm if (ret != ARCHIVE_OK) 596231200Smm return (ret); 597228753Smm } 598231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX) 599228753Smm /* If path exceeds PATH_MAX, shorten the path. */ 600228753Smm edit_deep_directories(a); 601228753Smm#endif 602228753Smm 603228753Smm ret = restore_entry(a); 604228753Smm 605248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) 606228753Smm /* 607248616Smm * Check if the filesystem the file is restoring on supports 608248616Smm * HFS+ Compression. If not, cancel HFS+ Compression. 609248616Smm */ 610248616Smm if (a->todo | TODO_HFS_COMPRESSION) { 611248616Smm /* 612248616Smm * NOTE: UF_COMPRESSED is ignored even if the filesystem 613248616Smm * supports HFS+ Compression because the file should 614248616Smm * have at least an extended attriute "com.apple.decmpfs" 615248616Smm * before the flag is set to indicate that the file have 616248616Smm * been compressed. If hte filesystem does not support 617248616Smm * HFS+ Compression the system call will fail. 618248616Smm */ 619248616Smm if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0) 620248616Smm a->todo &= ~TODO_HFS_COMPRESSION; 621248616Smm } 622248616Smm#endif 623248616Smm 624248616Smm /* 625228753Smm * TODO: There are rumours that some extended attributes must 626228753Smm * be restored before file data is written. If this is true, 627228753Smm * then we either need to write all extended attributes both 628228753Smm * before and after restoring the data, or find some rule for 629228753Smm * determining which must go first and which last. Due to the 630228753Smm * many ways people are using xattrs, this may prove to be an 631228753Smm * intractable problem. 632228753Smm */ 633228753Smm 634228753Smm#ifdef HAVE_FCHDIR 635228753Smm /* If we changed directory above, restore it here. */ 636228753Smm if (a->restore_pwd >= 0) { 637228753Smm r = fchdir(a->restore_pwd); 638228753Smm if (r != 0) { 639228753Smm archive_set_error(&a->archive, errno, "chdir() failure"); 640228753Smm ret = ARCHIVE_FATAL; 641228753Smm } 642228753Smm close(a->restore_pwd); 643228753Smm a->restore_pwd = -1; 644228753Smm } 645228753Smm#endif 646228753Smm 647228753Smm /* 648228753Smm * Fixup uses the unedited pathname from archive_entry_pathname(), 649228753Smm * because it is relative to the base dir and the edited path 650228753Smm * might be relative to some intermediate dir as a result of the 651228753Smm * deep restore logic. 652228753Smm */ 653228753Smm if (a->deferred & TODO_MODE) { 654228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 655248616Smm if (fe == NULL) 656248616Smm return (ARCHIVE_FATAL); 657228753Smm fe->fixup |= TODO_MODE_BASE; 658228753Smm fe->mode = a->mode; 659228753Smm } 660228753Smm 661228753Smm if ((a->deferred & TODO_TIMES) 662228753Smm && (archive_entry_mtime_is_set(entry) 663228753Smm || archive_entry_atime_is_set(entry))) { 664228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 665248616Smm if (fe == NULL) 666248616Smm return (ARCHIVE_FATAL); 667231200Smm fe->mode = a->mode; 668228753Smm fe->fixup |= TODO_TIMES; 669228753Smm if (archive_entry_atime_is_set(entry)) { 670228753Smm fe->atime = archive_entry_atime(entry); 671228753Smm fe->atime_nanos = archive_entry_atime_nsec(entry); 672228753Smm } else { 673228753Smm /* If atime is unset, use start time. */ 674228753Smm fe->atime = a->start_time; 675228753Smm fe->atime_nanos = 0; 676228753Smm } 677228753Smm if (archive_entry_mtime_is_set(entry)) { 678228753Smm fe->mtime = archive_entry_mtime(entry); 679228753Smm fe->mtime_nanos = archive_entry_mtime_nsec(entry); 680228753Smm } else { 681228753Smm /* If mtime is unset, use start time. */ 682228753Smm fe->mtime = a->start_time; 683228753Smm fe->mtime_nanos = 0; 684228753Smm } 685228753Smm if (archive_entry_birthtime_is_set(entry)) { 686228753Smm fe->birthtime = archive_entry_birthtime(entry); 687228753Smm fe->birthtime_nanos = archive_entry_birthtime_nsec(entry); 688228753Smm } else { 689228753Smm /* If birthtime is unset, use mtime. */ 690228753Smm fe->birthtime = fe->mtime; 691228753Smm fe->birthtime_nanos = fe->mtime_nanos; 692228753Smm } 693228753Smm } 694228753Smm 695231200Smm if (a->deferred & TODO_ACLS) { 696231200Smm fe = current_fixup(a, archive_entry_pathname(entry)); 697248616Smm if (fe == NULL) 698248616Smm return (ARCHIVE_FATAL); 699238909Smm fe->fixup |= TODO_ACLS; 700231200Smm archive_acl_copy(&fe->acl, archive_entry_acl(entry)); 701231200Smm } 702231200Smm 703231200Smm if (a->deferred & TODO_MAC_METADATA) { 704231200Smm const void *metadata; 705231200Smm size_t metadata_size; 706231200Smm metadata = archive_entry_mac_metadata(a->entry, &metadata_size); 707231200Smm if (metadata != NULL && metadata_size > 0) { 708231200Smm fe = current_fixup(a, archive_entry_pathname(entry)); 709248616Smm if (fe == NULL) 710248616Smm return (ARCHIVE_FATAL); 711231200Smm fe->mac_metadata = malloc(metadata_size); 712231200Smm if (fe->mac_metadata != NULL) { 713231200Smm memcpy(fe->mac_metadata, metadata, metadata_size); 714231200Smm fe->mac_metadata_size = metadata_size; 715231200Smm fe->fixup |= TODO_MAC_METADATA; 716231200Smm } 717231200Smm } 718231200Smm } 719231200Smm 720228753Smm if (a->deferred & TODO_FFLAGS) { 721228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 722248616Smm if (fe == NULL) 723248616Smm return (ARCHIVE_FATAL); 724228753Smm fe->fixup |= TODO_FFLAGS; 725228753Smm /* TODO: Complete this.. defer fflags from below. */ 726228753Smm } 727228753Smm 728228753Smm /* We've created the object and are ready to pour data into it. */ 729228753Smm if (ret >= ARCHIVE_WARN) 730228753Smm a->archive.state = ARCHIVE_STATE_DATA; 731228753Smm /* 732228753Smm * If it's not open, tell our client not to try writing. 733228753Smm * In particular, dirs, links, etc, don't get written to. 734228753Smm */ 735228753Smm if (a->fd < 0) { 736228753Smm archive_entry_set_size(entry, 0); 737228753Smm a->filesize = 0; 738228753Smm } 739228753Smm 740228753Smm return (ret); 741228753Smm} 742228753Smm 743228753Smmint 744231200Smmarchive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i) 745228753Smm{ 746228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 747231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 748228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file"); 749231200Smm a->skip_file_set = 1; 750228753Smm a->skip_file_dev = d; 751228753Smm a->skip_file_ino = i; 752228753Smm return (ARCHIVE_OK); 753228753Smm} 754228753Smm 755228753Smmstatic ssize_t 756228753Smmwrite_data_block(struct archive_write_disk *a, const char *buff, size_t size) 757228753Smm{ 758228753Smm uint64_t start_size = size; 759228753Smm ssize_t bytes_written = 0; 760228753Smm ssize_t block_size = 0, bytes_to_write; 761228753Smm 762228753Smm if (size == 0) 763228753Smm return (ARCHIVE_OK); 764228753Smm 765228753Smm if (a->filesize == 0 || a->fd < 0) { 766228753Smm archive_set_error(&a->archive, 0, 767228753Smm "Attempt to write to an empty file"); 768228753Smm return (ARCHIVE_WARN); 769228753Smm } 770228753Smm 771228753Smm if (a->flags & ARCHIVE_EXTRACT_SPARSE) { 772228753Smm#if HAVE_STRUCT_STAT_ST_BLKSIZE 773228753Smm int r; 774231200Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 775228753Smm return (r); 776228753Smm block_size = a->pst->st_blksize; 777228753Smm#else 778228753Smm /* XXX TODO XXX Is there a more appropriate choice here ? */ 779228753Smm /* This needn't match the filesystem allocation size. */ 780228753Smm block_size = 16*1024; 781228753Smm#endif 782228753Smm } 783228753Smm 784228753Smm /* If this write would run beyond the file size, truncate it. */ 785231200Smm if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) 786228753Smm start_size = size = (size_t)(a->filesize - a->offset); 787228753Smm 788228753Smm /* Write the data. */ 789228753Smm while (size > 0) { 790228753Smm if (block_size == 0) { 791228753Smm bytes_to_write = size; 792228753Smm } else { 793228753Smm /* We're sparsifying the file. */ 794228753Smm const char *p, *end; 795231200Smm int64_t block_end; 796228753Smm 797228753Smm /* Skip leading zero bytes. */ 798228753Smm for (p = buff, end = buff + size; p < end; ++p) { 799228753Smm if (*p != '\0') 800228753Smm break; 801228753Smm } 802228753Smm a->offset += p - buff; 803228753Smm size -= p - buff; 804228753Smm buff = p; 805228753Smm if (size == 0) 806228753Smm break; 807228753Smm 808228753Smm /* Calculate next block boundary after offset. */ 809228753Smm block_end 810228753Smm = (a->offset / block_size + 1) * block_size; 811228753Smm 812228753Smm /* If the adjusted write would cross block boundary, 813228753Smm * truncate it to the block boundary. */ 814228753Smm bytes_to_write = size; 815228753Smm if (a->offset + bytes_to_write > block_end) 816228753Smm bytes_to_write = block_end - a->offset; 817228753Smm } 818228753Smm /* Seek if necessary to the specified offset. */ 819228753Smm if (a->offset != a->fd_offset) { 820228753Smm if (lseek(a->fd, a->offset, SEEK_SET) < 0) { 821228753Smm archive_set_error(&a->archive, errno, 822228753Smm "Seek failed"); 823228753Smm return (ARCHIVE_FATAL); 824228753Smm } 825228753Smm a->fd_offset = a->offset; 826231200Smm } 827228753Smm bytes_written = write(a->fd, buff, bytes_to_write); 828228753Smm if (bytes_written < 0) { 829228753Smm archive_set_error(&a->archive, errno, "Write failed"); 830228753Smm return (ARCHIVE_WARN); 831228753Smm } 832228753Smm buff += bytes_written; 833228753Smm size -= bytes_written; 834231200Smm a->total_bytes_written += bytes_written; 835228753Smm a->offset += bytes_written; 836228753Smm a->fd_offset = a->offset; 837228753Smm } 838228753Smm return (start_size - size); 839228753Smm} 840228753Smm 841248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ 842248616Smm && defined(HAVE_ZLIB_H) 843248616Smm 844248616Smm/* 845248616Smm * Set UF_COMPRESSED file flag. 846248616Smm * This have to be called after hfs_write_decmpfs() because if the 847248616Smm * file does not have "com.apple.decmpfs" xattr the flag is ignored. 848248616Smm */ 849248616Smmstatic int 850248616Smmhfs_set_compressed_fflag(struct archive_write_disk *a) 851248616Smm{ 852248616Smm int r; 853248616Smm 854248616Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 855248616Smm return (r); 856248616Smm 857248616Smm a->st.st_flags |= UF_COMPRESSED; 858248616Smm if (fchflags(a->fd, a->st.st_flags) != 0) { 859248616Smm archive_set_error(&a->archive, errno, 860248616Smm "Failed to set UF_COMPRESSED file flag"); 861248616Smm return (ARCHIVE_WARN); 862248616Smm } 863248616Smm return (ARCHIVE_OK); 864248616Smm} 865248616Smm 866248616Smm/* 867248616Smm * HFS+ Compression decmpfs 868248616Smm * 869248616Smm * +------------------------------+ +0 870248616Smm * | Magic(LE 4 bytes) | 871248616Smm * +------------------------------+ 872248616Smm * | Type(LE 4 bytes) | 873248616Smm * +------------------------------+ 874248616Smm * | Uncompressed size(LE 8 bytes)| 875248616Smm * +------------------------------+ +16 876248616Smm * | | 877248616Smm * | Compressed data | 878248616Smm * | (Placed only if Type == 3) | 879248616Smm * | | 880248616Smm * +------------------------------+ +3802 = MAX_DECMPFS_XATTR_SIZE 881248616Smm * 882248616Smm * Type is 3: decmpfs has compressed data. 883248616Smm * Type is 4: Resource Fork has compressed data. 884248616Smm */ 885248616Smm/* 886248616Smm * Write "com.apple.decmpfs" 887248616Smm */ 888248616Smmstatic int 889248616Smmhfs_write_decmpfs(struct archive_write_disk *a) 890248616Smm{ 891248616Smm int r; 892248616Smm uint32_t compression_type; 893248616Smm 894248616Smm r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p, 895248616Smm a->decmpfs_attr_size, 0, 0); 896248616Smm if (r < 0) { 897248616Smm archive_set_error(&a->archive, errno, 898248616Smm "Cannot restore xattr:%s", DECMPFS_XATTR_NAME); 899248616Smm compression_type = archive_le32dec( 900248616Smm &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]); 901248616Smm if (compression_type == CMP_RESOURCE_FORK) 902248616Smm fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 903248616Smm XATTR_SHOWCOMPRESSION); 904248616Smm return (ARCHIVE_WARN); 905248616Smm } 906248616Smm return (ARCHIVE_OK); 907248616Smm} 908248616Smm 909248616Smm/* 910248616Smm * HFS+ Compression Resource Fork 911248616Smm * 912248616Smm * +-----------------------------+ 913248616Smm * | Header(260 bytes) | 914248616Smm * +-----------------------------+ 915248616Smm * | Block count(LE 4 bytes) | 916248616Smm * +-----------------------------+ --+ 917248616Smm * +-- | Offset (LE 4 bytes) | | 918248616Smm * | | [distance from Block count] | | Block 0 919248616Smm * | +-----------------------------+ | 920248616Smm * | | Compressed size(LE 4 bytes) | | 921248616Smm * | +-----------------------------+ --+ 922248616Smm * | | | 923248616Smm * | | .................. | 924248616Smm * | | | 925248616Smm * | +-----------------------------+ --+ 926248616Smm * | | Offset (LE 4 bytes) | | 927248616Smm * | +-----------------------------+ | Block (Block count -1) 928248616Smm * | | Compressed size(LE 4 bytes) | | 929248616Smm * +-> +-----------------------------+ --+ 930248616Smm * | Compressed data(n bytes) | Block 0 931248616Smm * +-----------------------------+ 932248616Smm * | | 933248616Smm * | .................. | 934248616Smm * | | 935248616Smm * +-----------------------------+ 936248616Smm * | Compressed data(n bytes) | Block (Block count -1) 937248616Smm * +-----------------------------+ 938248616Smm * | Footer(50 bytes) | 939248616Smm * +-----------------------------+ 940248616Smm * 941248616Smm */ 942248616Smm/* 943248616Smm * Write the header of "com.apple.ResourceFork" 944248616Smm */ 945248616Smmstatic int 946248616Smmhfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff, 947248616Smm size_t bytes, uint32_t position) 948248616Smm{ 949248616Smm int ret; 950248616Smm 951248616Smm ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes, 952248616Smm position, a->rsrc_xattr_options); 953248616Smm if (ret < 0) { 954248616Smm archive_set_error(&a->archive, errno, 955248616Smm "Cannot restore xattr: %s at %u pos %u bytes", 956248616Smm XATTR_RESOURCEFORK_NAME, 957248616Smm (unsigned)position, 958248616Smm (unsigned)bytes); 959248616Smm return (ARCHIVE_WARN); 960248616Smm } 961248616Smm a->rsrc_xattr_options &= ~XATTR_CREATE; 962248616Smm return (ARCHIVE_OK); 963248616Smm} 964248616Smm 965248616Smmstatic int 966248616Smmhfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed) 967248616Smm{ 968248616Smm int ret; 969248616Smm 970248616Smm ret = hfs_write_resource_fork(a, a->compressed_buffer, 971248616Smm bytes_compressed, a->compressed_rsrc_position); 972248616Smm if (ret == ARCHIVE_OK) 973248616Smm a->compressed_rsrc_position += bytes_compressed; 974248616Smm return (ret); 975248616Smm} 976248616Smm 977248616Smmstatic int 978248616Smmhfs_write_resource_fork_header(struct archive_write_disk *a) 979248616Smm{ 980248616Smm unsigned char *buff; 981248616Smm uint32_t rsrc_bytes; 982248616Smm uint32_t rsrc_header_bytes; 983248616Smm 984248616Smm /* 985248616Smm * Write resource fork header + block info. 986248616Smm */ 987248616Smm buff = a->resource_fork; 988248616Smm rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE; 989248616Smm rsrc_header_bytes = 990248616Smm RSRC_H_SIZE + /* Header base size. */ 991248616Smm 4 + /* Block count. */ 992248616Smm (a->decmpfs_block_count * 8);/* Block info */ 993248616Smm archive_be32enc(buff, 0x100); 994248616Smm archive_be32enc(buff + 4, rsrc_bytes); 995248616Smm archive_be32enc(buff + 8, rsrc_bytes - 256); 996248616Smm archive_be32enc(buff + 12, 0x32); 997248616Smm memset(buff + 16, 0, 240); 998248616Smm archive_be32enc(buff + 256, rsrc_bytes - 260); 999248616Smm return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0); 1000248616Smm} 1001248616Smm 1002248616Smmstatic size_t 1003248616Smmhfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size) 1004248616Smm{ 1005248616Smm static const char rsrc_footer[RSRC_F_SIZE] = { 1006248616Smm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1007248616Smm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1008248616Smm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1009248616Smm 0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c', 'm', 1010248616Smm 'p', 'f', 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 1011248616Smm 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1012248616Smm 0x00, 0x00 1013248616Smm }; 1014248616Smm if (buff_size < sizeof(rsrc_footer)) 1015248616Smm return (0); 1016248616Smm memcpy(buff, rsrc_footer, sizeof(rsrc_footer)); 1017248616Smm return (sizeof(rsrc_footer)); 1018248616Smm} 1019248616Smm 1020248616Smmstatic int 1021248616Smmhfs_reset_compressor(struct archive_write_disk *a) 1022248616Smm{ 1023248616Smm int ret; 1024248616Smm 1025248616Smm if (a->stream_valid) 1026248616Smm ret = deflateReset(&a->stream); 1027248616Smm else 1028248616Smm ret = deflateInit(&a->stream, a->decmpfs_compression_level); 1029248616Smm 1030248616Smm if (ret != Z_OK) { 1031248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1032248616Smm "Failed to initialize compressor"); 1033248616Smm return (ARCHIVE_FATAL); 1034248616Smm } else 1035248616Smm a->stream_valid = 1; 1036248616Smm 1037248616Smm return (ARCHIVE_OK); 1038248616Smm} 1039248616Smm 1040248616Smmstatic int 1041248616Smmhfs_decompress(struct archive_write_disk *a) 1042248616Smm{ 1043248616Smm uint32_t *block_info; 1044248616Smm unsigned int block_count; 1045248616Smm uint32_t data_pos, data_size; 1046248616Smm ssize_t r; 1047248616Smm ssize_t bytes_written, bytes_to_write; 1048248616Smm unsigned char *b; 1049248616Smm 1050248616Smm block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE); 1051248616Smm block_count = archive_le32dec(block_info++); 1052248616Smm while (block_count--) { 1053248616Smm data_pos = RSRC_H_SIZE + archive_le32dec(block_info++); 1054248616Smm data_size = archive_le32dec(block_info++); 1055248616Smm r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME, 1056248616Smm a->compressed_buffer, data_size, data_pos, 0); 1057248616Smm if (r != data_size) { 1058248616Smm archive_set_error(&a->archive, 1059248616Smm (r < 0)?errno:ARCHIVE_ERRNO_MISC, 1060248616Smm "Failed to read resource fork"); 1061248616Smm return (ARCHIVE_WARN); 1062248616Smm } 1063248616Smm if (a->compressed_buffer[0] == 0xff) { 1064248616Smm bytes_to_write = data_size -1; 1065248616Smm b = a->compressed_buffer + 1; 1066248616Smm } else { 1067248616Smm uLong dest_len = MAX_DECMPFS_BLOCK_SIZE; 1068248616Smm int zr; 1069248616Smm 1070248616Smm zr = uncompress((Bytef *)a->uncompressed_buffer, 1071248616Smm &dest_len, a->compressed_buffer, data_size); 1072248616Smm if (zr != Z_OK) { 1073248616Smm archive_set_error(&a->archive, 1074248616Smm ARCHIVE_ERRNO_MISC, 1075248616Smm "Failed to decompress resource fork"); 1076248616Smm return (ARCHIVE_WARN); 1077248616Smm } 1078248616Smm bytes_to_write = dest_len; 1079248616Smm b = (unsigned char *)a->uncompressed_buffer; 1080248616Smm } 1081248616Smm do { 1082248616Smm bytes_written = write(a->fd, b, bytes_to_write); 1083248616Smm if (bytes_written < 0) { 1084248616Smm archive_set_error(&a->archive, errno, 1085248616Smm "Write failed"); 1086248616Smm return (ARCHIVE_WARN); 1087248616Smm } 1088248616Smm bytes_to_write -= bytes_written; 1089248616Smm b += bytes_written; 1090248616Smm } while (bytes_to_write > 0); 1091248616Smm } 1092248616Smm r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0); 1093248616Smm if (r == -1) { 1094248616Smm archive_set_error(&a->archive, errno, 1095248616Smm "Failed to remove resource fork"); 1096248616Smm return (ARCHIVE_WARN); 1097248616Smm } 1098248616Smm return (ARCHIVE_OK); 1099248616Smm} 1100248616Smm 1101248616Smmstatic int 1102248616Smmhfs_drive_compressor(struct archive_write_disk *a, const char *buff, 1103248616Smm size_t size) 1104248616Smm{ 1105248616Smm unsigned char *buffer_compressed; 1106248616Smm size_t bytes_compressed; 1107248616Smm size_t bytes_used; 1108248616Smm int ret; 1109248616Smm 1110248616Smm ret = hfs_reset_compressor(a); 1111248616Smm if (ret != ARCHIVE_OK) 1112248616Smm return (ret); 1113248616Smm 1114248616Smm if (a->compressed_buffer == NULL) { 1115248616Smm size_t block_size; 1116248616Smm 1117248616Smm block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE + 1118248616Smm + compressBound(MAX_DECMPFS_BLOCK_SIZE); 1119248616Smm a->compressed_buffer = malloc(block_size); 1120248616Smm if (a->compressed_buffer == NULL) { 1121248616Smm archive_set_error(&a->archive, ENOMEM, 1122248616Smm "Can't allocate memory for Resource Fork"); 1123248616Smm return (ARCHIVE_FATAL); 1124248616Smm } 1125248616Smm a->compressed_buffer_size = block_size; 1126248616Smm a->compressed_buffer_remaining = block_size; 1127248616Smm } 1128248616Smm 1129248616Smm buffer_compressed = a->compressed_buffer + 1130248616Smm a->compressed_buffer_size - a->compressed_buffer_remaining; 1131248616Smm a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff; 1132248616Smm a->stream.avail_in = size; 1133248616Smm a->stream.next_out = buffer_compressed; 1134248616Smm a->stream.avail_out = a->compressed_buffer_remaining; 1135248616Smm do { 1136248616Smm ret = deflate(&a->stream, Z_FINISH); 1137248616Smm switch (ret) { 1138248616Smm case Z_OK: 1139248616Smm case Z_STREAM_END: 1140248616Smm break; 1141248616Smm default: 1142248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1143248616Smm "Failed to compress data"); 1144248616Smm return (ARCHIVE_FAILED); 1145248616Smm } 1146248616Smm } while (ret == Z_OK); 1147248616Smm bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out; 1148248616Smm 1149248616Smm /* 1150248616Smm * If the compressed size is larger than the original size, 1151248616Smm * throw away compressed data, use uncompressed data instead. 1152248616Smm */ 1153248616Smm if (bytes_compressed > size) { 1154248616Smm buffer_compressed[0] = 0xFF;/* uncompressed marker. */ 1155248616Smm memcpy(buffer_compressed + 1, buff, size); 1156248616Smm bytes_compressed = size + 1; 1157248616Smm } 1158248616Smm a->compressed_buffer_remaining -= bytes_compressed; 1159248616Smm 1160248616Smm /* 1161248616Smm * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE 1162248616Smm * and the block count in the file is only one, store compressed 1163248616Smm * data to decmpfs xattr instead of the resource fork. 1164248616Smm */ 1165248616Smm if (a->decmpfs_block_count == 1 && 1166248616Smm (a->decmpfs_attr_size + bytes_compressed) 1167248616Smm <= MAX_DECMPFS_XATTR_SIZE) { 1168248616Smm archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], 1169248616Smm CMP_XATTR); 1170248616Smm memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE, 1171248616Smm buffer_compressed, bytes_compressed); 1172248616Smm a->decmpfs_attr_size += bytes_compressed; 1173248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size; 1174248616Smm /* 1175248616Smm * Finish HFS+ Compression. 1176248616Smm * - Write the decmpfs xattr. 1177248616Smm * - Set the UF_COMPRESSED file flag. 1178248616Smm */ 1179248616Smm ret = hfs_write_decmpfs(a); 1180248616Smm if (ret == ARCHIVE_OK) 1181248616Smm ret = hfs_set_compressed_fflag(a); 1182248616Smm return (ret); 1183248616Smm } 1184248616Smm 1185248616Smm /* Update block info. */ 1186248616Smm archive_le32enc(a->decmpfs_block_info++, 1187248616Smm a->compressed_rsrc_position_v - RSRC_H_SIZE); 1188248616Smm archive_le32enc(a->decmpfs_block_info++, bytes_compressed); 1189248616Smm a->compressed_rsrc_position_v += bytes_compressed; 1190248616Smm 1191248616Smm /* 1192248616Smm * Write the compressed data to the resource fork. 1193248616Smm */ 1194248616Smm bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining; 1195248616Smm while (bytes_used >= COMPRESSED_W_SIZE) { 1196248616Smm ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE); 1197248616Smm if (ret != ARCHIVE_OK) 1198248616Smm return (ret); 1199248616Smm bytes_used -= COMPRESSED_W_SIZE; 1200248616Smm if (bytes_used > COMPRESSED_W_SIZE) 1201248616Smm memmove(a->compressed_buffer, 1202248616Smm a->compressed_buffer + COMPRESSED_W_SIZE, 1203248616Smm bytes_used); 1204248616Smm else 1205248616Smm memcpy(a->compressed_buffer, 1206248616Smm a->compressed_buffer + COMPRESSED_W_SIZE, 1207248616Smm bytes_used); 1208248616Smm } 1209248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used; 1210248616Smm 1211248616Smm /* 1212248616Smm * If the current block is the last block, write the remaining 1213248616Smm * compressed data and the resource fork footer. 1214248616Smm */ 1215248616Smm if (a->file_remaining_bytes == 0) { 1216248616Smm size_t rsrc_size; 1217248616Smm int64_t bk; 1218248616Smm 1219248616Smm /* Append the resource footer. */ 1220248616Smm rsrc_size = hfs_set_resource_fork_footer( 1221248616Smm a->compressed_buffer + bytes_used, 1222248616Smm a->compressed_buffer_remaining); 1223248616Smm ret = hfs_write_compressed_data(a, bytes_used + rsrc_size); 1224248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size; 1225248616Smm 1226248616Smm /* If the compressed size is not enouph smaller than 1227248616Smm * the uncompressed size. cancel HFS+ compression. 1228248616Smm * TODO: study a behavior of ditto utility and improve 1229248616Smm * the condition to fall back into no HFS+ compression. */ 1230248616Smm bk = HFS_BLOCKS(a->compressed_rsrc_position); 1231248616Smm bk += bk >> 7; 1232248616Smm if (bk > HFS_BLOCKS(a->filesize)) 1233248616Smm return hfs_decompress(a); 1234248616Smm /* 1235248616Smm * Write the resourcefork header. 1236248616Smm */ 1237248616Smm if (ret == ARCHIVE_OK) 1238248616Smm ret = hfs_write_resource_fork_header(a); 1239248616Smm /* 1240248616Smm * Finish HFS+ Compression. 1241248616Smm * - Write the decmpfs xattr. 1242248616Smm * - Set the UF_COMPRESSED file flag. 1243248616Smm */ 1244248616Smm if (ret == ARCHIVE_OK) 1245248616Smm ret = hfs_write_decmpfs(a); 1246248616Smm if (ret == ARCHIVE_OK) 1247248616Smm ret = hfs_set_compressed_fflag(a); 1248248616Smm } 1249248616Smm return (ret); 1250248616Smm} 1251248616Smm 1252228753Smmstatic ssize_t 1253248616Smmhfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff, 1254248616Smm size_t size) 1255248616Smm{ 1256248616Smm const char *buffer_to_write; 1257248616Smm size_t bytes_to_write; 1258248616Smm int ret; 1259248616Smm 1260248616Smm if (a->decmpfs_block_count == (unsigned)-1) { 1261248616Smm void *new_block; 1262248616Smm size_t new_size; 1263248616Smm unsigned int block_count; 1264248616Smm 1265248616Smm if (a->decmpfs_header_p == NULL) { 1266248616Smm new_block = malloc(MAX_DECMPFS_XATTR_SIZE 1267248616Smm + sizeof(uint32_t)); 1268248616Smm if (new_block == NULL) { 1269248616Smm archive_set_error(&a->archive, ENOMEM, 1270248616Smm "Can't allocate memory for decmpfs"); 1271248616Smm return (ARCHIVE_FATAL); 1272248616Smm } 1273248616Smm a->decmpfs_header_p = new_block; 1274248616Smm } 1275248616Smm a->decmpfs_attr_size = DECMPFS_HEADER_SIZE; 1276248616Smm archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC], 1277248616Smm DECMPFS_MAGIC); 1278248616Smm archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], 1279248616Smm CMP_RESOURCE_FORK); 1280248616Smm archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE], 1281248616Smm a->filesize); 1282248616Smm 1283248616Smm /* Calculate a block count of the file. */ 1284248616Smm block_count = 1285248616Smm (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) / 1286248616Smm MAX_DECMPFS_BLOCK_SIZE; 1287248616Smm /* 1288248616Smm * Allocate buffer for resource fork. 1289248616Smm * Set up related pointers; 1290248616Smm */ 1291248616Smm new_size = 1292248616Smm RSRC_H_SIZE + /* header */ 1293248616Smm 4 + /* Block count */ 1294248616Smm (block_count * sizeof(uint32_t) * 2) + 1295248616Smm RSRC_F_SIZE; /* footer */ 1296248616Smm if (new_size > a->resource_fork_allocated_size) { 1297248616Smm new_block = realloc(a->resource_fork, new_size); 1298248616Smm if (new_block == NULL) { 1299248616Smm archive_set_error(&a->archive, ENOMEM, 1300248616Smm "Can't allocate memory for ResourceFork"); 1301248616Smm return (ARCHIVE_FATAL); 1302248616Smm } 1303248616Smm a->resource_fork_allocated_size = new_size; 1304248616Smm a->resource_fork = new_block; 1305248616Smm } 1306248616Smm 1307248616Smm /* Allocate uncompressed buffer */ 1308248616Smm if (a->uncompressed_buffer == NULL) { 1309248616Smm new_block = malloc(MAX_DECMPFS_BLOCK_SIZE); 1310248616Smm if (new_block == NULL) { 1311248616Smm archive_set_error(&a->archive, ENOMEM, 1312248616Smm "Can't allocate memory for decmpfs"); 1313248616Smm return (ARCHIVE_FATAL); 1314248616Smm } 1315248616Smm a->uncompressed_buffer = new_block; 1316248616Smm } 1317248616Smm a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; 1318248616Smm a->file_remaining_bytes = a->filesize; 1319248616Smm a->compressed_buffer_remaining = a->compressed_buffer_size; 1320248616Smm 1321248616Smm /* 1322248616Smm * Set up a resource fork. 1323248616Smm */ 1324248616Smm a->rsrc_xattr_options = XATTR_CREATE; 1325248616Smm /* Get the position where we are going to set a bunch 1326248616Smm * of block info. */ 1327248616Smm a->decmpfs_block_info = 1328248616Smm (uint32_t *)(a->resource_fork + RSRC_H_SIZE); 1329248616Smm /* Set the block count to the resource fork. */ 1330248616Smm archive_le32enc(a->decmpfs_block_info++, block_count); 1331248616Smm /* Get the position where we are goint to set compressed 1332248616Smm * data. */ 1333248616Smm a->compressed_rsrc_position = 1334248616Smm RSRC_H_SIZE + 4 + (block_count * 8); 1335248616Smm a->compressed_rsrc_position_v = a->compressed_rsrc_position; 1336248616Smm a->decmpfs_block_count = block_count; 1337248616Smm } 1338248616Smm 1339248616Smm /* Ignore redundant bytes. */ 1340248616Smm if (a->file_remaining_bytes == 0) 1341248616Smm return ((ssize_t)size); 1342248616Smm 1343248616Smm /* Do not overrun a block size. */ 1344248616Smm if (size > a->block_remaining_bytes) 1345248616Smm bytes_to_write = a->block_remaining_bytes; 1346248616Smm else 1347248616Smm bytes_to_write = size; 1348248616Smm /* Do not overrun the file size. */ 1349248616Smm if (bytes_to_write > a->file_remaining_bytes) 1350248616Smm bytes_to_write = a->file_remaining_bytes; 1351248616Smm 1352248616Smm /* For efficiency, if a copy length is full of the uncompressed 1353248616Smm * buffer size, do not copy writing data to it. */ 1354248616Smm if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE) 1355248616Smm buffer_to_write = buff; 1356248616Smm else { 1357248616Smm memcpy(a->uncompressed_buffer + 1358248616Smm MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes, 1359248616Smm buff, bytes_to_write); 1360248616Smm buffer_to_write = a->uncompressed_buffer; 1361248616Smm } 1362248616Smm a->block_remaining_bytes -= bytes_to_write; 1363248616Smm a->file_remaining_bytes -= bytes_to_write; 1364248616Smm 1365248616Smm if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) { 1366248616Smm ret = hfs_drive_compressor(a, buffer_to_write, 1367248616Smm MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes); 1368248616Smm if (ret < 0) 1369248616Smm return (ret); 1370248616Smm a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; 1371248616Smm } 1372248616Smm /* Ignore redundant bytes. */ 1373248616Smm if (a->file_remaining_bytes == 0) 1374248616Smm return ((ssize_t)size); 1375248616Smm return (bytes_to_write); 1376248616Smm} 1377248616Smm 1378248616Smmstatic ssize_t 1379248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff, 1380248616Smm size_t size) 1381248616Smm{ 1382248616Smm uint64_t start_size = size; 1383248616Smm ssize_t bytes_written = 0; 1384248616Smm ssize_t bytes_to_write; 1385248616Smm 1386248616Smm if (size == 0) 1387248616Smm return (ARCHIVE_OK); 1388248616Smm 1389248616Smm if (a->filesize == 0 || a->fd < 0) { 1390248616Smm archive_set_error(&a->archive, 0, 1391248616Smm "Attempt to write to an empty file"); 1392248616Smm return (ARCHIVE_WARN); 1393248616Smm } 1394248616Smm 1395248616Smm /* If this write would run beyond the file size, truncate it. */ 1396248616Smm if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) 1397248616Smm start_size = size = (size_t)(a->filesize - a->offset); 1398248616Smm 1399248616Smm /* Write the data. */ 1400248616Smm while (size > 0) { 1401248616Smm bytes_to_write = size; 1402248616Smm /* Seek if necessary to the specified offset. */ 1403248616Smm if (a->offset < a->fd_offset) { 1404248616Smm /* Can't support backword move. */ 1405248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1406248616Smm "Seek failed"); 1407248616Smm return (ARCHIVE_FATAL); 1408248616Smm } else if (a->offset > a->fd_offset) { 1409248616Smm int64_t skip = a->offset - a->fd_offset; 1410248616Smm char nullblock[1024]; 1411248616Smm 1412248616Smm memset(nullblock, 0, sizeof(nullblock)); 1413248616Smm while (skip > 0) { 1414248616Smm if (skip > (int64_t)sizeof(nullblock)) 1415248616Smm bytes_written = hfs_write_decmpfs_block( 1416248616Smm a, nullblock, sizeof(nullblock)); 1417248616Smm else 1418248616Smm bytes_written = hfs_write_decmpfs_block( 1419248616Smm a, nullblock, skip); 1420248616Smm if (bytes_written < 0) { 1421248616Smm archive_set_error(&a->archive, errno, 1422248616Smm "Write failed"); 1423248616Smm return (ARCHIVE_WARN); 1424248616Smm } 1425248616Smm skip -= bytes_written; 1426248616Smm } 1427248616Smm 1428248616Smm a->fd_offset = a->offset; 1429248616Smm } 1430248616Smm bytes_written = 1431248616Smm hfs_write_decmpfs_block(a, buff, bytes_to_write); 1432248616Smm if (bytes_written < 0) 1433248616Smm return (bytes_written); 1434248616Smm buff += bytes_written; 1435248616Smm size -= bytes_written; 1436248616Smm a->total_bytes_written += bytes_written; 1437248616Smm a->offset += bytes_written; 1438248616Smm a->fd_offset = a->offset; 1439248616Smm } 1440248616Smm return (start_size - size); 1441248616Smm} 1442248616Smm#else 1443248616Smmstatic ssize_t 1444248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff, 1445248616Smm size_t size) 1446248616Smm{ 1447248616Smm return (write_data_block(a, buff, size)); 1448248616Smm} 1449248616Smm#endif 1450248616Smm 1451248616Smmstatic ssize_t 1452231200Smm_archive_write_disk_data_block(struct archive *_a, 1453231200Smm const void *buff, size_t size, int64_t offset) 1454228753Smm{ 1455228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1456228753Smm ssize_t r; 1457228753Smm 1458231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1459231200Smm ARCHIVE_STATE_DATA, "archive_write_data_block"); 1460228753Smm 1461228753Smm a->offset = offset; 1462248616Smm if (a->todo & TODO_HFS_COMPRESSION) 1463248616Smm r = hfs_write_data_block(a, buff, size); 1464248616Smm else 1465248616Smm r = write_data_block(a, buff, size); 1466228753Smm if (r < ARCHIVE_OK) 1467228753Smm return (r); 1468228753Smm if ((size_t)r < size) { 1469228753Smm archive_set_error(&a->archive, 0, 1470228753Smm "Write request too large"); 1471228753Smm return (ARCHIVE_WARN); 1472228753Smm } 1473228753Smm return (ARCHIVE_OK); 1474228753Smm} 1475228753Smm 1476228753Smmstatic ssize_t 1477231200Smm_archive_write_disk_data(struct archive *_a, const void *buff, size_t size) 1478228753Smm{ 1479228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1480228753Smm 1481231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1482228753Smm ARCHIVE_STATE_DATA, "archive_write_data"); 1483228753Smm 1484248616Smm if (a->todo & TODO_HFS_COMPRESSION) 1485248616Smm return (hfs_write_data_block(a, buff, size)); 1486228753Smm return (write_data_block(a, buff, size)); 1487228753Smm} 1488228753Smm 1489228753Smmstatic int 1490231200Smm_archive_write_disk_finish_entry(struct archive *_a) 1491228753Smm{ 1492228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1493228753Smm int ret = ARCHIVE_OK; 1494228753Smm 1495231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1496228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1497228753Smm "archive_write_finish_entry"); 1498228753Smm if (a->archive.state & ARCHIVE_STATE_HEADER) 1499228753Smm return (ARCHIVE_OK); 1500228753Smm archive_clear_error(&a->archive); 1501228753Smm 1502228753Smm /* Pad or truncate file to the right size. */ 1503228753Smm if (a->fd < 0) { 1504228753Smm /* There's no file. */ 1505228753Smm } else if (a->filesize < 0) { 1506228753Smm /* File size is unknown, so we can't set the size. */ 1507228753Smm } else if (a->fd_offset == a->filesize) { 1508228753Smm /* Last write ended at exactly the filesize; we're done. */ 1509228753Smm /* Hopefully, this is the common case. */ 1510248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) 1511248616Smm } else if (a->todo & TODO_HFS_COMPRESSION) { 1512248616Smm char null_d[1024]; 1513248616Smm ssize_t r; 1514248616Smm 1515248616Smm if (a->file_remaining_bytes) 1516248616Smm memset(null_d, 0, sizeof(null_d)); 1517248616Smm while (a->file_remaining_bytes) { 1518248616Smm if (a->file_remaining_bytes > sizeof(null_d)) 1519248616Smm r = hfs_write_data_block( 1520248616Smm a, null_d, sizeof(null_d)); 1521248616Smm else 1522248616Smm r = hfs_write_data_block( 1523248616Smm a, null_d, a->file_remaining_bytes); 1524248616Smm if (r < 0) 1525248616Smm return ((int)r); 1526248616Smm } 1527248616Smm#endif 1528228753Smm } else { 1529228753Smm#if HAVE_FTRUNCATE 1530228753Smm if (ftruncate(a->fd, a->filesize) == -1 && 1531228753Smm a->filesize == 0) { 1532228753Smm archive_set_error(&a->archive, errno, 1533228753Smm "File size could not be restored"); 1534228753Smm return (ARCHIVE_FAILED); 1535228753Smm } 1536228753Smm#endif 1537228753Smm /* 1538228753Smm * Not all platforms implement the XSI option to 1539228753Smm * extend files via ftruncate. Stat() the file again 1540228753Smm * to see what happened. 1541228753Smm */ 1542228753Smm a->pst = NULL; 1543231200Smm if ((ret = lazy_stat(a)) != ARCHIVE_OK) 1544228753Smm return (ret); 1545228753Smm /* We can use lseek()/write() to extend the file if 1546228753Smm * ftruncate didn't work or isn't available. */ 1547228753Smm if (a->st.st_size < a->filesize) { 1548228753Smm const char nul = '\0'; 1549228753Smm if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) { 1550228753Smm archive_set_error(&a->archive, errno, 1551228753Smm "Seek failed"); 1552228753Smm return (ARCHIVE_FATAL); 1553228753Smm } 1554228753Smm if (write(a->fd, &nul, 1) < 0) { 1555228753Smm archive_set_error(&a->archive, errno, 1556228753Smm "Write to restore size failed"); 1557228753Smm return (ARCHIVE_FATAL); 1558228753Smm } 1559228753Smm a->pst = NULL; 1560228753Smm } 1561228753Smm } 1562228753Smm 1563228753Smm /* Restore metadata. */ 1564228753Smm 1565228753Smm /* 1566248616Smm * This is specific to Mac OS X. 1567248616Smm * If the current file is an AppleDouble file, it should be 1568248616Smm * linked with the data fork file and remove it. 1569248616Smm */ 1570248616Smm if (a->todo & TODO_APPLEDOUBLE) { 1571248616Smm int r2 = fixup_appledouble(a, a->name); 1572248616Smm if (r2 == ARCHIVE_EOF) { 1573248616Smm /* The current file has been successfully linked 1574248616Smm * with the data fork file and removed. So there 1575248616Smm * is nothing to do on the current file. */ 1576248616Smm goto finish_metadata; 1577248616Smm } 1578248616Smm if (r2 < ret) ret = r2; 1579248616Smm } 1580248616Smm 1581248616Smm /* 1582228753Smm * Look up the "real" UID only if we're going to need it. 1583228753Smm * TODO: the TODO_SGID condition can be dropped here, can't it? 1584228753Smm */ 1585228753Smm if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { 1586231200Smm a->uid = archive_write_disk_uid(&a->archive, 1587228753Smm archive_entry_uname(a->entry), 1588228753Smm archive_entry_uid(a->entry)); 1589228753Smm } 1590228753Smm /* Look up the "real" GID only if we're going to need it. */ 1591228753Smm /* TODO: the TODO_SUID condition can be dropped here, can't it? */ 1592228753Smm if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { 1593231200Smm a->gid = archive_write_disk_gid(&a->archive, 1594228753Smm archive_entry_gname(a->entry), 1595228753Smm archive_entry_gid(a->entry)); 1596228753Smm } 1597231200Smm 1598228753Smm /* 1599231200Smm * Restore ownership before set_mode tries to restore suid/sgid 1600228753Smm * bits. If we set the owner, we know what it is and can skip 1601228753Smm * a stat() call to examine the ownership of the file on disk. 1602228753Smm */ 1603248616Smm if (a->todo & TODO_OWNER) { 1604248616Smm int r2 = set_ownership(a); 1605248616Smm if (r2 < ret) ret = r2; 1606248616Smm } 1607231200Smm 1608231200Smm /* 1609231200Smm * set_mode must precede ACLs on systems such as Solaris and 1610231200Smm * FreeBSD where setting the mode implicitly clears extended ACLs 1611231200Smm */ 1612228753Smm if (a->todo & TODO_MODE) { 1613228753Smm int r2 = set_mode(a, a->mode); 1614228753Smm if (r2 < ret) ret = r2; 1615228753Smm } 1616228753Smm 1617228753Smm /* 1618228753Smm * Security-related extended attributes (such as 1619228753Smm * security.capability on Linux) have to be restored last, 1620228753Smm * since they're implicitly removed by other file changes. 1621228753Smm */ 1622228753Smm if (a->todo & TODO_XATTR) { 1623228753Smm int r2 = set_xattrs(a); 1624228753Smm if (r2 < ret) ret = r2; 1625228753Smm } 1626228753Smm 1627228753Smm /* 1628228753Smm * Some flags prevent file modification; they must be restored after 1629228753Smm * file contents are written. 1630228753Smm */ 1631228753Smm if (a->todo & TODO_FFLAGS) { 1632228753Smm int r2 = set_fflags(a); 1633228753Smm if (r2 < ret) ret = r2; 1634228753Smm } 1635231200Smm 1636228753Smm /* 1637231200Smm * Time must follow most other metadata; 1638228753Smm * otherwise atime will get changed. 1639228753Smm */ 1640228753Smm if (a->todo & TODO_TIMES) { 1641231200Smm int r2 = set_times_from_entry(a); 1642228753Smm if (r2 < ret) ret = r2; 1643228753Smm } 1644228753Smm 1645231200Smm /* 1646231200Smm * Mac extended metadata includes ACLs. 1647231200Smm */ 1648231200Smm if (a->todo & TODO_MAC_METADATA) { 1649231200Smm const void *metadata; 1650231200Smm size_t metadata_size; 1651231200Smm metadata = archive_entry_mac_metadata(a->entry, &metadata_size); 1652231200Smm if (metadata != NULL && metadata_size > 0) { 1653248616Smm int r2 = set_mac_metadata(a, archive_entry_pathname( 1654248616Smm a->entry), metadata, metadata_size); 1655231200Smm if (r2 < ret) ret = r2; 1656231200Smm } 1657231200Smm } 1658231200Smm 1659231200Smm /* 1660231200Smm * ACLs must be restored after timestamps because there are 1661231200Smm * ACLs that prevent attribute changes (including time). 1662231200Smm */ 1663231200Smm if (a->todo & TODO_ACLS) { 1664238909Smm int r2 = archive_write_disk_set_acls(&a->archive, a->fd, 1665231200Smm archive_entry_pathname(a->entry), 1666231200Smm archive_entry_acl(a->entry)); 1667231200Smm if (r2 < ret) ret = r2; 1668231200Smm } 1669231200Smm 1670248616Smmfinish_metadata: 1671228753Smm /* If there's an fd, we can close it now. */ 1672228753Smm if (a->fd >= 0) { 1673228753Smm close(a->fd); 1674228753Smm a->fd = -1; 1675228753Smm } 1676228753Smm /* If there's an entry, we can release it now. */ 1677228753Smm if (a->entry) { 1678228753Smm archive_entry_free(a->entry); 1679228753Smm a->entry = NULL; 1680228753Smm } 1681228753Smm a->archive.state = ARCHIVE_STATE_HEADER; 1682228753Smm return (ret); 1683228753Smm} 1684228753Smm 1685228753Smmint 1686228753Smmarchive_write_disk_set_group_lookup(struct archive *_a, 1687228753Smm void *private_data, 1688231200Smm int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid), 1689228753Smm void (*cleanup_gid)(void *private)) 1690228753Smm{ 1691228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1692231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1693228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); 1694228753Smm 1695231200Smm if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) 1696231200Smm (a->cleanup_gid)(a->lookup_gid_data); 1697231200Smm 1698228753Smm a->lookup_gid = lookup_gid; 1699228753Smm a->cleanup_gid = cleanup_gid; 1700228753Smm a->lookup_gid_data = private_data; 1701228753Smm return (ARCHIVE_OK); 1702228753Smm} 1703228753Smm 1704228753Smmint 1705228753Smmarchive_write_disk_set_user_lookup(struct archive *_a, 1706228753Smm void *private_data, 1707231200Smm int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid), 1708228753Smm void (*cleanup_uid)(void *private)) 1709228753Smm{ 1710228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1711231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1712228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); 1713228753Smm 1714231200Smm if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) 1715231200Smm (a->cleanup_uid)(a->lookup_uid_data); 1716231200Smm 1717228753Smm a->lookup_uid = lookup_uid; 1718228753Smm a->cleanup_uid = cleanup_uid; 1719228753Smm a->lookup_uid_data = private_data; 1720228753Smm return (ARCHIVE_OK); 1721228753Smm} 1722228753Smm 1723231200Smmint64_t 1724231200Smmarchive_write_disk_gid(struct archive *_a, const char *name, int64_t id) 1725231200Smm{ 1726231200Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1727231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1728231200Smm ARCHIVE_STATE_ANY, "archive_write_disk_gid"); 1729231200Smm if (a->lookup_gid) 1730231200Smm return (a->lookup_gid)(a->lookup_gid_data, name, id); 1731231200Smm return (id); 1732231200Smm} 1733231200Smm 1734231200Smmint64_t 1735231200Smmarchive_write_disk_uid(struct archive *_a, const char *name, int64_t id) 1736231200Smm{ 1737238909Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1738238909Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1739238909Smm ARCHIVE_STATE_ANY, "archive_write_disk_uid"); 1740238909Smm if (a->lookup_uid) 1741238909Smm return (a->lookup_uid)(a->lookup_uid_data, name, id); 1742238909Smm return (id); 1743231200Smm} 1744228753Smm 1745228753Smm/* 1746228753Smm * Create a new archive_write_disk object and initialize it with global state. 1747228753Smm */ 1748228753Smmstruct archive * 1749228753Smmarchive_write_disk_new(void) 1750228753Smm{ 1751228753Smm struct archive_write_disk *a; 1752228753Smm 1753228753Smm a = (struct archive_write_disk *)malloc(sizeof(*a)); 1754228753Smm if (a == NULL) 1755228753Smm return (NULL); 1756228753Smm memset(a, 0, sizeof(*a)); 1757228753Smm a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; 1758228753Smm /* We're ready to write a header immediately. */ 1759228753Smm a->archive.state = ARCHIVE_STATE_HEADER; 1760228753Smm a->archive.vtable = archive_write_disk_vtable(); 1761228753Smm a->start_time = time(NULL); 1762231200Smm /* Query and restore the umask. */ 1763231200Smm umask(a->user_umask = umask(0)); 1764228753Smm#ifdef HAVE_GETEUID 1765228753Smm a->user_uid = geteuid(); 1766228753Smm#endif /* HAVE_GETEUID */ 1767228753Smm if (archive_string_ensure(&a->path_safe, 512) == NULL) { 1768228753Smm free(a); 1769228753Smm return (NULL); 1770228753Smm } 1771248616Smm#ifdef HAVE_ZLIB_H 1772248616Smm a->decmpfs_compression_level = 5; 1773248616Smm#endif 1774228753Smm return (&a->archive); 1775228753Smm} 1776228753Smm 1777228753Smm 1778228753Smm/* 1779228753Smm * If pathname is longer than PATH_MAX, chdir to a suitable 1780228753Smm * intermediate dir and edit the path down to a shorter suffix. Note 1781228753Smm * that this routine never returns an error; if the chdir() attempt 1782228753Smm * fails for any reason, we just go ahead with the long pathname. The 1783228753Smm * object creation is likely to fail, but any error will get handled 1784228753Smm * at that time. 1785228753Smm */ 1786231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX) 1787228753Smmstatic void 1788228753Smmedit_deep_directories(struct archive_write_disk *a) 1789228753Smm{ 1790228753Smm int ret; 1791228753Smm char *tail = a->name; 1792228753Smm 1793228753Smm /* If path is short, avoid the open() below. */ 1794228753Smm if (strlen(tail) <= PATH_MAX) 1795228753Smm return; 1796228753Smm 1797228753Smm /* Try to record our starting dir. */ 1798248616Smm a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC); 1799248616Smm __archive_ensure_cloexec_flag(a->restore_pwd); 1800228753Smm if (a->restore_pwd < 0) 1801228753Smm return; 1802228753Smm 1803228753Smm /* As long as the path is too long... */ 1804228753Smm while (strlen(tail) > PATH_MAX) { 1805228753Smm /* Locate a dir prefix shorter than PATH_MAX. */ 1806228753Smm tail += PATH_MAX - 8; 1807228753Smm while (tail > a->name && *tail != '/') 1808228753Smm tail--; 1809228753Smm /* Exit if we find a too-long path component. */ 1810228753Smm if (tail <= a->name) 1811228753Smm return; 1812228753Smm /* Create the intermediate dir and chdir to it. */ 1813228753Smm *tail = '\0'; /* Terminate dir portion */ 1814228753Smm ret = create_dir(a, a->name); 1815228753Smm if (ret == ARCHIVE_OK && chdir(a->name) != 0) 1816228753Smm ret = ARCHIVE_FAILED; 1817228753Smm *tail = '/'; /* Restore the / we removed. */ 1818228753Smm if (ret != ARCHIVE_OK) 1819228753Smm return; 1820228753Smm tail++; 1821228753Smm /* The chdir() succeeded; we've now shortened the path. */ 1822228753Smm a->name = tail; 1823228753Smm } 1824228753Smm return; 1825228753Smm} 1826228753Smm#endif 1827228753Smm 1828228753Smm/* 1829228753Smm * The main restore function. 1830228753Smm */ 1831228753Smmstatic int 1832228753Smmrestore_entry(struct archive_write_disk *a) 1833228753Smm{ 1834228753Smm int ret = ARCHIVE_OK, en; 1835228753Smm 1836228753Smm if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { 1837228753Smm /* 1838228753Smm * TODO: Fix this. Apparently, there are platforms 1839228753Smm * that still allow root to hose the entire filesystem 1840228753Smm * by unlinking a dir. The S_ISDIR() test above 1841228753Smm * prevents us from using unlink() here if the new 1842228753Smm * object is a dir, but that doesn't mean the old 1843228753Smm * object isn't a dir. 1844228753Smm */ 1845228753Smm if (unlink(a->name) == 0) { 1846228753Smm /* We removed it, reset cached stat. */ 1847228753Smm a->pst = NULL; 1848228753Smm } else if (errno == ENOENT) { 1849228753Smm /* File didn't exist, that's just as good. */ 1850228753Smm } else if (rmdir(a->name) == 0) { 1851228753Smm /* It was a dir, but now it's gone. */ 1852228753Smm a->pst = NULL; 1853228753Smm } else { 1854228753Smm /* We tried, but couldn't get rid of it. */ 1855228753Smm archive_set_error(&a->archive, errno, 1856228753Smm "Could not unlink"); 1857228753Smm return(ARCHIVE_FAILED); 1858228753Smm } 1859228753Smm } 1860228753Smm 1861228753Smm /* Try creating it first; if this fails, we'll try to recover. */ 1862228753Smm en = create_filesystem_object(a); 1863228753Smm 1864228753Smm if ((en == ENOTDIR || en == ENOENT) 1865228753Smm && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) { 1866228753Smm /* If the parent dir doesn't exist, try creating it. */ 1867228753Smm create_parent_dir(a, a->name); 1868228753Smm /* Now try to create the object again. */ 1869228753Smm en = create_filesystem_object(a); 1870228753Smm } 1871228753Smm 1872228753Smm if ((en == EISDIR || en == EEXIST) 1873228753Smm && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { 1874228753Smm /* If we're not overwriting, we're done. */ 1875231200Smm archive_entry_unset_size(a->entry); 1876231200Smm return (ARCHIVE_OK); 1877228753Smm } 1878228753Smm 1879228753Smm /* 1880228753Smm * Some platforms return EISDIR if you call 1881228753Smm * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some 1882228753Smm * return EEXIST. POSIX is ambiguous, requiring EISDIR 1883228753Smm * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT) 1884228753Smm * on an existing item. 1885228753Smm */ 1886228753Smm if (en == EISDIR) { 1887228753Smm /* A dir is in the way of a non-dir, rmdir it. */ 1888228753Smm if (rmdir(a->name) != 0) { 1889228753Smm archive_set_error(&a->archive, errno, 1890228753Smm "Can't remove already-existing dir"); 1891228753Smm return (ARCHIVE_FAILED); 1892228753Smm } 1893228753Smm a->pst = NULL; 1894228753Smm /* Try again. */ 1895228753Smm en = create_filesystem_object(a); 1896228753Smm } else if (en == EEXIST) { 1897228753Smm /* 1898228753Smm * We know something is in the way, but we don't know what; 1899228753Smm * we need to find out before we go any further. 1900228753Smm */ 1901228753Smm int r = 0; 1902228753Smm /* 1903231200Smm * The SECURE_SYMLINKS logic has already removed a 1904228753Smm * symlink to a dir if the client wants that. So 1905228753Smm * follow the symlink if we're creating a dir. 1906228753Smm */ 1907228753Smm if (S_ISDIR(a->mode)) 1908228753Smm r = stat(a->name, &a->st); 1909228753Smm /* 1910228753Smm * If it's not a dir (or it's a broken symlink), 1911228753Smm * then don't follow it. 1912228753Smm */ 1913228753Smm if (r != 0 || !S_ISDIR(a->mode)) 1914228753Smm r = lstat(a->name, &a->st); 1915228753Smm if (r != 0) { 1916228753Smm archive_set_error(&a->archive, errno, 1917228753Smm "Can't stat existing object"); 1918228753Smm return (ARCHIVE_FAILED); 1919228753Smm } 1920228753Smm 1921228753Smm /* 1922228753Smm * NO_OVERWRITE_NEWER doesn't apply to directories. 1923228753Smm */ 1924228753Smm if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) 1925228753Smm && !S_ISDIR(a->st.st_mode)) { 1926228753Smm if (!older(&(a->st), a->entry)) { 1927231200Smm archive_entry_unset_size(a->entry); 1928231200Smm return (ARCHIVE_OK); 1929228753Smm } 1930228753Smm } 1931228753Smm 1932228753Smm /* If it's our archive, we're done. */ 1933231200Smm if (a->skip_file_set && 1934238856Smm a->st.st_dev == (dev_t)a->skip_file_dev && 1935238856Smm a->st.st_ino == (ino_t)a->skip_file_ino) { 1936238856Smm archive_set_error(&a->archive, 0, 1937238856Smm "Refusing to overwrite archive"); 1938228753Smm return (ARCHIVE_FAILED); 1939228753Smm } 1940228753Smm 1941228753Smm if (!S_ISDIR(a->st.st_mode)) { 1942228753Smm /* A non-dir is in the way, unlink it. */ 1943228753Smm if (unlink(a->name) != 0) { 1944228753Smm archive_set_error(&a->archive, errno, 1945228753Smm "Can't unlink already-existing object"); 1946228753Smm return (ARCHIVE_FAILED); 1947228753Smm } 1948228753Smm a->pst = NULL; 1949228753Smm /* Try again. */ 1950228753Smm en = create_filesystem_object(a); 1951228753Smm } else if (!S_ISDIR(a->mode)) { 1952228753Smm /* A dir is in the way of a non-dir, rmdir it. */ 1953228753Smm if (rmdir(a->name) != 0) { 1954228753Smm archive_set_error(&a->archive, errno, 1955238856Smm "Can't replace existing directory with non-directory"); 1956228753Smm return (ARCHIVE_FAILED); 1957228753Smm } 1958228753Smm /* Try again. */ 1959228753Smm en = create_filesystem_object(a); 1960228753Smm } else { 1961228753Smm /* 1962228753Smm * There's a dir in the way of a dir. Don't 1963228753Smm * waste time with rmdir()/mkdir(), just fix 1964228753Smm * up the permissions on the existing dir. 1965228753Smm * Note that we don't change perms on existing 1966228753Smm * dirs unless _EXTRACT_PERM is specified. 1967228753Smm */ 1968228753Smm if ((a->mode != a->st.st_mode) 1969228753Smm && (a->todo & TODO_MODE_FORCE)) 1970228753Smm a->deferred |= (a->todo & TODO_MODE); 1971228753Smm /* Ownership doesn't need deferred fixup. */ 1972228753Smm en = 0; /* Forget the EEXIST. */ 1973228753Smm } 1974228753Smm } 1975228753Smm 1976228753Smm if (en) { 1977228753Smm /* Everything failed; give up here. */ 1978228753Smm archive_set_error(&a->archive, en, "Can't create '%s'", 1979228753Smm a->name); 1980228753Smm return (ARCHIVE_FAILED); 1981228753Smm } 1982228753Smm 1983228753Smm a->pst = NULL; /* Cached stat data no longer valid. */ 1984228753Smm return (ret); 1985228753Smm} 1986228753Smm 1987228753Smm/* 1988228753Smm * Returns 0 if creation succeeds, or else returns errno value from 1989228753Smm * the failed system call. Note: This function should only ever perform 1990228753Smm * a single system call. 1991228753Smm */ 1992228753Smmstatic int 1993228753Smmcreate_filesystem_object(struct archive_write_disk *a) 1994228753Smm{ 1995228753Smm /* Create the entry. */ 1996228753Smm const char *linkname; 1997228753Smm mode_t final_mode, mode; 1998228753Smm int r; 1999228753Smm 2000228753Smm /* We identify hard/symlinks according to the link names. */ 2001228753Smm /* Since link(2) and symlink(2) don't handle modes, we're done here. */ 2002228753Smm linkname = archive_entry_hardlink(a->entry); 2003228753Smm if (linkname != NULL) { 2004228753Smm#if !HAVE_LINK 2005228753Smm return (EPERM); 2006228753Smm#else 2007228753Smm r = link(linkname, a->name) ? errno : 0; 2008228753Smm /* 2009228753Smm * New cpio and pax formats allow hardlink entries 2010228753Smm * to carry data, so we may have to open the file 2011228753Smm * for hardlink entries. 2012228753Smm * 2013228753Smm * If the hardlink was successfully created and 2014228753Smm * the archive doesn't have carry data for it, 2015231200Smm * consider it to be non-authoritative for meta data. 2016228753Smm * This is consistent with GNU tar and BSD pax. 2017228753Smm * If the hardlink does carry data, let the last 2018228753Smm * archive entry decide ownership. 2019228753Smm */ 2020228753Smm if (r == 0 && a->filesize <= 0) { 2021228753Smm a->todo = 0; 2022228753Smm a->deferred = 0; 2023231200Smm } else if (r == 0 && a->filesize > 0) { 2024248616Smm a->fd = open(a->name, 2025248616Smm O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC); 2026248616Smm __archive_ensure_cloexec_flag(a->fd); 2027228753Smm if (a->fd < 0) 2028228753Smm r = errno; 2029228753Smm } 2030228753Smm return (r); 2031228753Smm#endif 2032228753Smm } 2033228753Smm linkname = archive_entry_symlink(a->entry); 2034228753Smm if (linkname != NULL) { 2035228753Smm#if HAVE_SYMLINK 2036228753Smm return symlink(linkname, a->name) ? errno : 0; 2037228753Smm#else 2038228753Smm return (EPERM); 2039228753Smm#endif 2040228753Smm } 2041228753Smm 2042228753Smm /* 2043228753Smm * The remaining system calls all set permissions, so let's 2044228753Smm * try to take advantage of that to avoid an extra chmod() 2045228753Smm * call. (Recall that umask is set to zero right now!) 2046228753Smm */ 2047228753Smm 2048228753Smm /* Mode we want for the final restored object (w/o file type bits). */ 2049228753Smm final_mode = a->mode & 07777; 2050228753Smm /* 2051228753Smm * The mode that will actually be restored in this step. Note 2052228753Smm * that SUID, SGID, etc, require additional work to ensure 2053228753Smm * security, so we never restore them at this point. 2054228753Smm */ 2055248616Smm mode = final_mode & 0777 & ~a->user_umask; 2056228753Smm 2057228753Smm switch (a->mode & AE_IFMT) { 2058228753Smm default: 2059228753Smm /* POSIX requires that we fall through here. */ 2060228753Smm /* FALLTHROUGH */ 2061228753Smm case AE_IFREG: 2062228753Smm a->fd = open(a->name, 2063248616Smm O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode); 2064248616Smm __archive_ensure_cloexec_flag(a->fd); 2065228753Smm r = (a->fd < 0); 2066228753Smm break; 2067228753Smm case AE_IFCHR: 2068228753Smm#ifdef HAVE_MKNOD 2069228753Smm /* Note: we use AE_IFCHR for the case label, and 2070228753Smm * S_IFCHR for the mknod() call. This is correct. */ 2071228753Smm r = mknod(a->name, mode | S_IFCHR, 2072228753Smm archive_entry_rdev(a->entry)); 2073228753Smm break; 2074228753Smm#else 2075228753Smm /* TODO: Find a better way to warn about our inability 2076228753Smm * to restore a char device node. */ 2077228753Smm return (EINVAL); 2078228753Smm#endif /* HAVE_MKNOD */ 2079228753Smm case AE_IFBLK: 2080228753Smm#ifdef HAVE_MKNOD 2081228753Smm r = mknod(a->name, mode | S_IFBLK, 2082228753Smm archive_entry_rdev(a->entry)); 2083228753Smm break; 2084228753Smm#else 2085228753Smm /* TODO: Find a better way to warn about our inability 2086228753Smm * to restore a block device node. */ 2087228753Smm return (EINVAL); 2088228753Smm#endif /* HAVE_MKNOD */ 2089228753Smm case AE_IFDIR: 2090228753Smm mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; 2091228753Smm r = mkdir(a->name, mode); 2092228753Smm if (r == 0) { 2093228753Smm /* Defer setting dir times. */ 2094228753Smm a->deferred |= (a->todo & TODO_TIMES); 2095228753Smm a->todo &= ~TODO_TIMES; 2096228753Smm /* Never use an immediate chmod(). */ 2097228753Smm /* We can't avoid the chmod() entirely if EXTRACT_PERM 2098228753Smm * because of SysV SGID inheritance. */ 2099228753Smm if ((mode != final_mode) 2100228753Smm || (a->flags & ARCHIVE_EXTRACT_PERM)) 2101228753Smm a->deferred |= (a->todo & TODO_MODE); 2102228753Smm a->todo &= ~TODO_MODE; 2103228753Smm } 2104228753Smm break; 2105228753Smm case AE_IFIFO: 2106228753Smm#ifdef HAVE_MKFIFO 2107228753Smm r = mkfifo(a->name, mode); 2108228753Smm break; 2109228753Smm#else 2110228753Smm /* TODO: Find a better way to warn about our inability 2111228753Smm * to restore a fifo. */ 2112228753Smm return (EINVAL); 2113228753Smm#endif /* HAVE_MKFIFO */ 2114228753Smm } 2115228753Smm 2116228753Smm /* All the system calls above set errno on failure. */ 2117228753Smm if (r) 2118228753Smm return (errno); 2119228753Smm 2120228753Smm /* If we managed to set the final mode, we've avoided a chmod(). */ 2121228753Smm if (mode == final_mode) 2122228753Smm a->todo &= ~TODO_MODE; 2123228753Smm return (0); 2124228753Smm} 2125228753Smm 2126228753Smm/* 2127228753Smm * Cleanup function for archive_extract. Mostly, this involves processing 2128228753Smm * the fixup list, which is used to address a number of problems: 2129228753Smm * * Dir permissions might prevent us from restoring a file in that 2130228753Smm * dir, so we restore the dir with minimum 0700 permissions first, 2131228753Smm * then correct the mode at the end. 2132228753Smm * * Similarly, the act of restoring a file touches the directory 2133228753Smm * and changes the timestamp on the dir, so we have to touch-up dir 2134228753Smm * timestamps at the end as well. 2135228753Smm * * Some file flags can interfere with the restore by, for example, 2136228753Smm * preventing the creation of hardlinks to those files. 2137231200Smm * * Mac OS extended metadata includes ACLs, so must be deferred on dirs. 2138228753Smm * 2139228753Smm * Note that tar/cpio do not require that archives be in a particular 2140228753Smm * order; there is no way to know when the last file has been restored 2141228753Smm * within a directory, so there's no way to optimize the memory usage 2142228753Smm * here by fixing up the directory any earlier than the 2143228753Smm * end-of-archive. 2144228753Smm * 2145228753Smm * XXX TODO: Directory ACLs should be restored here, for the same 2146228753Smm * reason we set directory perms here. XXX 2147228753Smm */ 2148228753Smmstatic int 2149231200Smm_archive_write_disk_close(struct archive *_a) 2150228753Smm{ 2151228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 2152228753Smm struct fixup_entry *next, *p; 2153228753Smm int ret; 2154228753Smm 2155231200Smm archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 2156228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 2157228753Smm "archive_write_disk_close"); 2158231200Smm ret = _archive_write_disk_finish_entry(&a->archive); 2159228753Smm 2160228753Smm /* Sort dir list so directories are fixed up in depth-first order. */ 2161228753Smm p = sort_dir_list(a->fixup_list); 2162228753Smm 2163228753Smm while (p != NULL) { 2164228753Smm a->pst = NULL; /* Mark stat cache as out-of-date. */ 2165228753Smm if (p->fixup & TODO_TIMES) { 2166231200Smm set_times(a, -1, p->mode, p->name, 2167231200Smm p->atime, p->atime_nanos, 2168231200Smm p->birthtime, p->birthtime_nanos, 2169231200Smm p->mtime, p->mtime_nanos, 2170231200Smm p->ctime, p->ctime_nanos); 2171228753Smm } 2172228753Smm if (p->fixup & TODO_MODE_BASE) 2173228753Smm chmod(p->name, p->mode); 2174231200Smm if (p->fixup & TODO_ACLS) 2175238909Smm archive_write_disk_set_acls(&a->archive, 2176238909Smm -1, p->name, &p->acl); 2177228753Smm if (p->fixup & TODO_FFLAGS) 2178228753Smm set_fflags_platform(a, -1, p->name, 2179228753Smm p->mode, p->fflags_set, 0); 2180231200Smm if (p->fixup & TODO_MAC_METADATA) 2181231200Smm set_mac_metadata(a, p->name, p->mac_metadata, 2182231200Smm p->mac_metadata_size); 2183228753Smm next = p->next; 2184231200Smm archive_acl_clear(&p->acl); 2185231200Smm free(p->mac_metadata); 2186228753Smm free(p->name); 2187228753Smm free(p); 2188228753Smm p = next; 2189228753Smm } 2190228753Smm a->fixup_list = NULL; 2191228753Smm return (ret); 2192228753Smm} 2193228753Smm 2194228753Smmstatic int 2195231200Smm_archive_write_disk_free(struct archive *_a) 2196228753Smm{ 2197231200Smm struct archive_write_disk *a; 2198228753Smm int ret; 2199231200Smm if (_a == NULL) 2200231200Smm return (ARCHIVE_OK); 2201231200Smm archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC, 2202231200Smm ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); 2203231200Smm a = (struct archive_write_disk *)_a; 2204231200Smm ret = _archive_write_disk_close(&a->archive); 2205231200Smm archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); 2206231200Smm archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); 2207228753Smm if (a->entry) 2208228753Smm archive_entry_free(a->entry); 2209228753Smm archive_string_free(&a->_name_data); 2210228753Smm archive_string_free(&a->archive.error_string); 2211228753Smm archive_string_free(&a->path_safe); 2212231200Smm a->archive.magic = 0; 2213231200Smm __archive_clean(&a->archive); 2214248616Smm free(a->decmpfs_header_p); 2215248616Smm free(a->resource_fork); 2216248616Smm free(a->compressed_buffer); 2217248616Smm free(a->uncompressed_buffer); 2218248616Smm#ifdef HAVE_ZLIB_H 2219248616Smm if (a->stream_valid) { 2220248616Smm switch (deflateEnd(&a->stream)) { 2221248616Smm case Z_OK: 2222248616Smm break; 2223248616Smm default: 2224248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 2225248616Smm "Failed to clean up compressor"); 2226248616Smm ret = ARCHIVE_FATAL; 2227248616Smm break; 2228248616Smm } 2229248616Smm } 2230248616Smm#endif 2231228753Smm free(a); 2232228753Smm return (ret); 2233228753Smm} 2234228753Smm 2235228753Smm/* 2236228753Smm * Simple O(n log n) merge sort to order the fixup list. In 2237228753Smm * particular, we want to restore dir timestamps depth-first. 2238228753Smm */ 2239228753Smmstatic struct fixup_entry * 2240228753Smmsort_dir_list(struct fixup_entry *p) 2241228753Smm{ 2242228753Smm struct fixup_entry *a, *b, *t; 2243228753Smm 2244228753Smm if (p == NULL) 2245228753Smm return (NULL); 2246228753Smm /* A one-item list is already sorted. */ 2247228753Smm if (p->next == NULL) 2248228753Smm return (p); 2249228753Smm 2250228753Smm /* Step 1: split the list. */ 2251228753Smm t = p; 2252228753Smm a = p->next->next; 2253228753Smm while (a != NULL) { 2254228753Smm /* Step a twice, t once. */ 2255228753Smm a = a->next; 2256228753Smm if (a != NULL) 2257228753Smm a = a->next; 2258228753Smm t = t->next; 2259228753Smm } 2260228753Smm /* Now, t is at the mid-point, so break the list here. */ 2261228753Smm b = t->next; 2262228753Smm t->next = NULL; 2263228753Smm a = p; 2264228753Smm 2265228753Smm /* Step 2: Recursively sort the two sub-lists. */ 2266228753Smm a = sort_dir_list(a); 2267228753Smm b = sort_dir_list(b); 2268228753Smm 2269228753Smm /* Step 3: Merge the returned lists. */ 2270228753Smm /* Pick the first element for the merged list. */ 2271228753Smm if (strcmp(a->name, b->name) > 0) { 2272228753Smm t = p = a; 2273228753Smm a = a->next; 2274228753Smm } else { 2275228753Smm t = p = b; 2276228753Smm b = b->next; 2277228753Smm } 2278228753Smm 2279228753Smm /* Always put the later element on the list first. */ 2280228753Smm while (a != NULL && b != NULL) { 2281228753Smm if (strcmp(a->name, b->name) > 0) { 2282228753Smm t->next = a; 2283228753Smm a = a->next; 2284228753Smm } else { 2285228753Smm t->next = b; 2286228753Smm b = b->next; 2287228753Smm } 2288228753Smm t = t->next; 2289228753Smm } 2290228753Smm 2291228753Smm /* Only one list is non-empty, so just splice it on. */ 2292228753Smm if (a != NULL) 2293228753Smm t->next = a; 2294228753Smm if (b != NULL) 2295228753Smm t->next = b; 2296228753Smm 2297228753Smm return (p); 2298228753Smm} 2299228753Smm 2300228753Smm/* 2301228753Smm * Returns a new, initialized fixup entry. 2302228753Smm * 2303228753Smm * TODO: Reduce the memory requirements for this list by using a tree 2304228753Smm * structure rather than a simple list of names. 2305228753Smm */ 2306228753Smmstatic struct fixup_entry * 2307228753Smmnew_fixup(struct archive_write_disk *a, const char *pathname) 2308228753Smm{ 2309228753Smm struct fixup_entry *fe; 2310228753Smm 2311231200Smm fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry)); 2312248616Smm if (fe == NULL) { 2313248616Smm archive_set_error(&a->archive, ENOMEM, 2314248616Smm "Can't allocate memory for a fixup"); 2315228753Smm return (NULL); 2316248616Smm } 2317228753Smm fe->next = a->fixup_list; 2318228753Smm a->fixup_list = fe; 2319228753Smm fe->fixup = 0; 2320228753Smm fe->name = strdup(pathname); 2321228753Smm return (fe); 2322228753Smm} 2323228753Smm 2324228753Smm/* 2325228753Smm * Returns a fixup structure for the current entry. 2326228753Smm */ 2327228753Smmstatic struct fixup_entry * 2328228753Smmcurrent_fixup(struct archive_write_disk *a, const char *pathname) 2329228753Smm{ 2330228753Smm if (a->current_fixup == NULL) 2331228753Smm a->current_fixup = new_fixup(a, pathname); 2332228753Smm return (a->current_fixup); 2333228753Smm} 2334228753Smm 2335228753Smm/* TODO: Make this work. */ 2336228753Smm/* 2337228753Smm * TODO: The deep-directory support bypasses this; disable deep directory 2338228753Smm * support if we're doing symlink checks. 2339228753Smm */ 2340228753Smm/* 2341228753Smm * TODO: Someday, integrate this with the deep dir support; they both 2342228753Smm * scan the path and both can be optimized by comparing against other 2343228753Smm * recent paths. 2344228753Smm */ 2345228753Smm/* TODO: Extend this to support symlinks on Windows Vista and later. */ 2346228753Smmstatic int 2347228753Smmcheck_symlinks(struct archive_write_disk *a) 2348228753Smm{ 2349228753Smm#if !defined(HAVE_LSTAT) 2350228753Smm /* Platform doesn't have lstat, so we can't look for symlinks. */ 2351228753Smm (void)a; /* UNUSED */ 2352228753Smm return (ARCHIVE_OK); 2353228753Smm#else 2354231200Smm char *pn; 2355228753Smm char c; 2356228753Smm int r; 2357228753Smm struct stat st; 2358228753Smm 2359228753Smm /* 2360228753Smm * Guard against symlink tricks. Reject any archive entry whose 2361228753Smm * destination would be altered by a symlink. 2362228753Smm */ 2363228753Smm /* Whatever we checked last time doesn't need to be re-checked. */ 2364228753Smm pn = a->name; 2365231200Smm if (archive_strlen(&(a->path_safe)) > 0) { 2366231200Smm char *p = a->path_safe.s; 2367231200Smm while ((*pn != '\0') && (*p == *pn)) 2368231200Smm ++p, ++pn; 2369231200Smm } 2370228753Smm c = pn[0]; 2371228753Smm /* Keep going until we've checked the entire name. */ 2372228753Smm while (pn[0] != '\0' && (pn[0] != '/' || pn[1] != '\0')) { 2373228753Smm /* Skip the next path element. */ 2374228753Smm while (*pn != '\0' && *pn != '/') 2375228753Smm ++pn; 2376228753Smm c = pn[0]; 2377228753Smm pn[0] = '\0'; 2378228753Smm /* Check that we haven't hit a symlink. */ 2379228753Smm r = lstat(a->name, &st); 2380228753Smm if (r != 0) { 2381228753Smm /* We've hit a dir that doesn't exist; stop now. */ 2382228753Smm if (errno == ENOENT) 2383228753Smm break; 2384228753Smm } else if (S_ISLNK(st.st_mode)) { 2385228753Smm if (c == '\0') { 2386228753Smm /* 2387228753Smm * Last element is symlink; remove it 2388228753Smm * so we can overwrite it with the 2389228753Smm * item being extracted. 2390228753Smm */ 2391228753Smm if (unlink(a->name)) { 2392228753Smm archive_set_error(&a->archive, errno, 2393228753Smm "Could not remove symlink %s", 2394228753Smm a->name); 2395228753Smm pn[0] = c; 2396228753Smm return (ARCHIVE_FAILED); 2397228753Smm } 2398228753Smm a->pst = NULL; 2399228753Smm /* 2400228753Smm * Even if we did remove it, a warning 2401228753Smm * is in order. The warning is silly, 2402228753Smm * though, if we're just replacing one 2403228753Smm * symlink with another symlink. 2404228753Smm */ 2405228753Smm if (!S_ISLNK(a->mode)) { 2406228753Smm archive_set_error(&a->archive, 0, 2407228753Smm "Removing symlink %s", 2408228753Smm a->name); 2409228753Smm } 2410228753Smm /* Symlink gone. No more problem! */ 2411228753Smm pn[0] = c; 2412228753Smm return (0); 2413228753Smm } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) { 2414228753Smm /* User asked us to remove problems. */ 2415228753Smm if (unlink(a->name) != 0) { 2416228753Smm archive_set_error(&a->archive, 0, 2417228753Smm "Cannot remove intervening symlink %s", 2418228753Smm a->name); 2419228753Smm pn[0] = c; 2420228753Smm return (ARCHIVE_FAILED); 2421228753Smm } 2422228753Smm a->pst = NULL; 2423228753Smm } else { 2424228753Smm archive_set_error(&a->archive, 0, 2425228753Smm "Cannot extract through symlink %s", 2426228753Smm a->name); 2427228753Smm pn[0] = c; 2428228753Smm return (ARCHIVE_FAILED); 2429228753Smm } 2430228753Smm } 2431228753Smm } 2432228753Smm pn[0] = c; 2433228753Smm /* We've checked and/or cleaned the whole path, so remember it. */ 2434228753Smm archive_strcpy(&a->path_safe, a->name); 2435228753Smm return (ARCHIVE_OK); 2436228753Smm#endif 2437228753Smm} 2438228753Smm 2439231200Smm#if defined(__CYGWIN__) 2440228753Smm/* 2441228753Smm * 1. Convert a path separator from '\' to '/' . 2442231200Smm * We shouldn't check multibyte character directly because some 2443228753Smm * character-set have been using the '\' character for a part of 2444228753Smm * its multibyte character code. 2445228753Smm * 2. Replace unusable characters in Windows with underscore('_'). 2446228753Smm * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx 2447228753Smm */ 2448231200Smmstatic void 2449228753Smmcleanup_pathname_win(struct archive_write_disk *a) 2450228753Smm{ 2451228753Smm wchar_t wc; 2452228753Smm char *p; 2453228753Smm size_t alen, l; 2454231200Smm int mb, complete, utf8; 2455228753Smm 2456231200Smm alen = 0; 2457231200Smm mb = 0; 2458231200Smm complete = 1; 2459231200Smm utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0; 2460231200Smm for (p = a->name; *p != '\0'; p++) { 2461231200Smm ++alen; 2462231200Smm if (*p == '\\') { 2463231200Smm /* If previous byte is smaller than 128, 2464231200Smm * this is not second byte of multibyte characters, 2465231200Smm * so we can replace '\' with '/'. */ 2466231200Smm if (utf8 || !mb) 2467231200Smm *p = '/'; 2468228753Smm else 2469231200Smm complete = 0;/* uncompleted. */ 2470231200Smm } else if (*(unsigned char *)p > 127) 2471231200Smm mb = 1; 2472231200Smm else 2473231200Smm mb = 0; 2474231200Smm /* Rewrite the path name if its next character is unusable. */ 2475228753Smm if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || 2476228753Smm *p == '<' || *p == '>' || *p == '|') 2477228753Smm *p = '_'; 2478228753Smm } 2479231200Smm if (complete) 2480231200Smm return; 2481231200Smm 2482228753Smm /* 2483231200Smm * Convert path separator in wide-character. 2484228753Smm */ 2485228753Smm p = a->name; 2486228753Smm while (*p != '\0' && alen) { 2487228753Smm l = mbtowc(&wc, p, alen); 2488232153Smm if (l == (size_t)-1) { 2489228753Smm while (*p != '\0') { 2490228753Smm if (*p == '\\') 2491228753Smm *p = '/'; 2492228753Smm ++p; 2493228753Smm } 2494228753Smm break; 2495228753Smm } 2496228753Smm if (l == 1 && wc == L'\\') 2497228753Smm *p = '/'; 2498228753Smm p += l; 2499228753Smm alen -= l; 2500228753Smm } 2501228753Smm} 2502228753Smm#endif 2503228753Smm 2504228753Smm/* 2505228753Smm * Canonicalize the pathname. In particular, this strips duplicate 2506228753Smm * '/' characters, '.' elements, and trailing '/'. It also raises an 2507228753Smm * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is 2508228753Smm * set) any '..' in the path. 2509228753Smm */ 2510228753Smmstatic int 2511228753Smmcleanup_pathname(struct archive_write_disk *a) 2512228753Smm{ 2513228753Smm char *dest, *src; 2514228753Smm char separator = '\0'; 2515228753Smm 2516228753Smm dest = src = a->name; 2517228753Smm if (*src == '\0') { 2518228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 2519228753Smm "Invalid empty pathname"); 2520228753Smm return (ARCHIVE_FAILED); 2521228753Smm } 2522228753Smm 2523231200Smm#if defined(__CYGWIN__) 2524231200Smm cleanup_pathname_win(a); 2525228753Smm#endif 2526228753Smm /* Skip leading '/'. */ 2527228753Smm if (*src == '/') 2528228753Smm separator = *src++; 2529228753Smm 2530228753Smm /* Scan the pathname one element at a time. */ 2531228753Smm for (;;) { 2532228753Smm /* src points to first char after '/' */ 2533228753Smm if (src[0] == '\0') { 2534228753Smm break; 2535228753Smm } else if (src[0] == '/') { 2536228753Smm /* Found '//', ignore second one. */ 2537228753Smm src++; 2538228753Smm continue; 2539228753Smm } else if (src[0] == '.') { 2540228753Smm if (src[1] == '\0') { 2541228753Smm /* Ignore trailing '.' */ 2542228753Smm break; 2543228753Smm } else if (src[1] == '/') { 2544228753Smm /* Skip './'. */ 2545228753Smm src += 2; 2546228753Smm continue; 2547228753Smm } else if (src[1] == '.') { 2548228753Smm if (src[2] == '/' || src[2] == '\0') { 2549228753Smm /* Conditionally warn about '..' */ 2550228753Smm if (a->flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) { 2551228753Smm archive_set_error(&a->archive, 2552228753Smm ARCHIVE_ERRNO_MISC, 2553228753Smm "Path contains '..'"); 2554228753Smm return (ARCHIVE_FAILED); 2555228753Smm } 2556228753Smm } 2557228753Smm /* 2558228753Smm * Note: Under no circumstances do we 2559228753Smm * remove '..' elements. In 2560228753Smm * particular, restoring 2561228753Smm * '/foo/../bar/' should create the 2562228753Smm * 'foo' dir as a side-effect. 2563228753Smm */ 2564228753Smm } 2565228753Smm } 2566228753Smm 2567228753Smm /* Copy current element, including leading '/'. */ 2568228753Smm if (separator) 2569228753Smm *dest++ = '/'; 2570228753Smm while (*src != '\0' && *src != '/') { 2571228753Smm *dest++ = *src++; 2572228753Smm } 2573228753Smm 2574228753Smm if (*src == '\0') 2575228753Smm break; 2576228753Smm 2577228753Smm /* Skip '/' separator. */ 2578228753Smm separator = *src++; 2579228753Smm } 2580228753Smm /* 2581228753Smm * We've just copied zero or more path elements, not including the 2582228753Smm * final '/'. 2583228753Smm */ 2584228753Smm if (dest == a->name) { 2585228753Smm /* 2586228753Smm * Nothing got copied. The path must have been something 2587228753Smm * like '.' or '/' or './' or '/././././/./'. 2588228753Smm */ 2589228753Smm if (separator) 2590228753Smm *dest++ = '/'; 2591228753Smm else 2592228753Smm *dest++ = '.'; 2593228753Smm } 2594228753Smm /* Terminate the result. */ 2595228753Smm *dest = '\0'; 2596228753Smm return (ARCHIVE_OK); 2597228753Smm} 2598228753Smm 2599228753Smm/* 2600228753Smm * Create the parent directory of the specified path, assuming path 2601228753Smm * is already in mutable storage. 2602228753Smm */ 2603228753Smmstatic int 2604228753Smmcreate_parent_dir(struct archive_write_disk *a, char *path) 2605228753Smm{ 2606228753Smm char *slash; 2607228753Smm int r; 2608228753Smm 2609228753Smm /* Remove tail element to obtain parent name. */ 2610228753Smm slash = strrchr(path, '/'); 2611228753Smm if (slash == NULL) 2612228753Smm return (ARCHIVE_OK); 2613228753Smm *slash = '\0'; 2614228753Smm r = create_dir(a, path); 2615228753Smm *slash = '/'; 2616228753Smm return (r); 2617228753Smm} 2618228753Smm 2619228753Smm/* 2620228753Smm * Create the specified dir, recursing to create parents as necessary. 2621228753Smm * 2622228753Smm * Returns ARCHIVE_OK if the path exists when we're done here. 2623228753Smm * Otherwise, returns ARCHIVE_FAILED. 2624228753Smm * Assumes path is in mutable storage; path is unchanged on exit. 2625228753Smm */ 2626228753Smmstatic int 2627228753Smmcreate_dir(struct archive_write_disk *a, char *path) 2628228753Smm{ 2629228753Smm struct stat st; 2630228753Smm struct fixup_entry *le; 2631228753Smm char *slash, *base; 2632228753Smm mode_t mode_final, mode; 2633228753Smm int r; 2634228753Smm 2635228753Smm /* Check for special names and just skip them. */ 2636228753Smm slash = strrchr(path, '/'); 2637228753Smm if (slash == NULL) 2638228753Smm base = path; 2639228753Smm else 2640228753Smm base = slash + 1; 2641228753Smm 2642228753Smm if (base[0] == '\0' || 2643228753Smm (base[0] == '.' && base[1] == '\0') || 2644228753Smm (base[0] == '.' && base[1] == '.' && base[2] == '\0')) { 2645228753Smm /* Don't bother trying to create null path, '.', or '..'. */ 2646228753Smm if (slash != NULL) { 2647228753Smm *slash = '\0'; 2648228753Smm r = create_dir(a, path); 2649228753Smm *slash = '/'; 2650228753Smm return (r); 2651228753Smm } 2652228753Smm return (ARCHIVE_OK); 2653228753Smm } 2654228753Smm 2655228753Smm /* 2656228753Smm * Yes, this should be stat() and not lstat(). Using lstat() 2657228753Smm * here loses the ability to extract through symlinks. Also note 2658228753Smm * that this should not use the a->st cache. 2659228753Smm */ 2660228753Smm if (stat(path, &st) == 0) { 2661228753Smm if (S_ISDIR(st.st_mode)) 2662228753Smm return (ARCHIVE_OK); 2663228753Smm if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { 2664228753Smm archive_set_error(&a->archive, EEXIST, 2665228753Smm "Can't create directory '%s'", path); 2666228753Smm return (ARCHIVE_FAILED); 2667228753Smm } 2668228753Smm if (unlink(path) != 0) { 2669228753Smm archive_set_error(&a->archive, errno, 2670228753Smm "Can't create directory '%s': " 2671231200Smm "Conflicting file cannot be removed", 2672231200Smm path); 2673228753Smm return (ARCHIVE_FAILED); 2674228753Smm } 2675228753Smm } else if (errno != ENOENT && errno != ENOTDIR) { 2676228753Smm /* Stat failed? */ 2677228753Smm archive_set_error(&a->archive, errno, "Can't test directory '%s'", path); 2678228753Smm return (ARCHIVE_FAILED); 2679228753Smm } else if (slash != NULL) { 2680228753Smm *slash = '\0'; 2681228753Smm r = create_dir(a, path); 2682228753Smm *slash = '/'; 2683228753Smm if (r != ARCHIVE_OK) 2684228753Smm return (r); 2685228753Smm } 2686228753Smm 2687228753Smm /* 2688228753Smm * Mode we want for the final restored directory. Per POSIX, 2689228753Smm * implicitly-created dirs must be created obeying the umask. 2690228753Smm * There's no mention whether this is different for privileged 2691228753Smm * restores (which the rest of this code handles by pretending 2692228753Smm * umask=0). I've chosen here to always obey the user's umask for 2693228753Smm * implicit dirs, even if _EXTRACT_PERM was specified. 2694228753Smm */ 2695228753Smm mode_final = DEFAULT_DIR_MODE & ~a->user_umask; 2696228753Smm /* Mode we want on disk during the restore process. */ 2697228753Smm mode = mode_final; 2698228753Smm mode |= MINIMUM_DIR_MODE; 2699228753Smm mode &= MAXIMUM_DIR_MODE; 2700228753Smm if (mkdir(path, mode) == 0) { 2701228753Smm if (mode != mode_final) { 2702228753Smm le = new_fixup(a, path); 2703248616Smm if (le == NULL) 2704248616Smm return (ARCHIVE_FATAL); 2705228753Smm le->fixup |=TODO_MODE_BASE; 2706228753Smm le->mode = mode_final; 2707228753Smm } 2708228753Smm return (ARCHIVE_OK); 2709228753Smm } 2710228753Smm 2711228753Smm /* 2712228753Smm * Without the following check, a/b/../b/c/d fails at the 2713228753Smm * second visit to 'b', so 'd' can't be created. Note that we 2714228753Smm * don't add it to the fixup list here, as it's already been 2715228753Smm * added. 2716228753Smm */ 2717228753Smm if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) 2718228753Smm return (ARCHIVE_OK); 2719228753Smm 2720228753Smm archive_set_error(&a->archive, errno, "Failed to create dir '%s'", 2721228753Smm path); 2722228753Smm return (ARCHIVE_FAILED); 2723228753Smm} 2724228753Smm 2725228753Smm/* 2726228753Smm * Note: Although we can skip setting the user id if the desired user 2727228753Smm * id matches the current user, we cannot skip setting the group, as 2728228753Smm * many systems set the gid based on the containing directory. So 2729228753Smm * we have to perform a chown syscall if we want to set the SGID 2730228753Smm * bit. (The alternative is to stat() and then possibly chown(); it's 2731228753Smm * more efficient to skip the stat() and just always chown().) Note 2732228753Smm * that a successful chown() here clears the TODO_SGID_CHECK bit, which 2733228753Smm * allows set_mode to skip the stat() check for the GID. 2734228753Smm */ 2735228753Smmstatic int 2736228753Smmset_ownership(struct archive_write_disk *a) 2737228753Smm{ 2738228753Smm#ifndef __CYGWIN__ 2739228753Smm/* unfortunately, on win32 there is no 'root' user with uid 0, 2740228753Smm so we just have to try the chown and see if it works */ 2741228753Smm 2742228753Smm /* If we know we can't change it, don't bother trying. */ 2743228753Smm if (a->user_uid != 0 && a->user_uid != a->uid) { 2744228753Smm archive_set_error(&a->archive, errno, 2745231200Smm "Can't set UID=%jd", (intmax_t)a->uid); 2746228753Smm return (ARCHIVE_WARN); 2747228753Smm } 2748228753Smm#endif 2749228753Smm 2750228753Smm#ifdef HAVE_FCHOWN 2751228753Smm /* If we have an fd, we can avoid a race. */ 2752228753Smm if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) { 2753228753Smm /* We've set owner and know uid/gid are correct. */ 2754228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 2755228753Smm return (ARCHIVE_OK); 2756228753Smm } 2757228753Smm#endif 2758228753Smm 2759228753Smm /* We prefer lchown() but will use chown() if that's all we have. */ 2760228753Smm /* Of course, if we have neither, this will always fail. */ 2761228753Smm#ifdef HAVE_LCHOWN 2762228753Smm if (lchown(a->name, a->uid, a->gid) == 0) { 2763228753Smm /* We've set owner and know uid/gid are correct. */ 2764228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 2765228753Smm return (ARCHIVE_OK); 2766228753Smm } 2767228753Smm#elif HAVE_CHOWN 2768228753Smm if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) { 2769228753Smm /* We've set owner and know uid/gid are correct. */ 2770228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 2771228753Smm return (ARCHIVE_OK); 2772228753Smm } 2773228753Smm#endif 2774228753Smm 2775228753Smm archive_set_error(&a->archive, errno, 2776231200Smm "Can't set user=%jd/group=%jd for %s", 2777231200Smm (intmax_t)a->uid, (intmax_t)a->gid, a->name); 2778228753Smm return (ARCHIVE_WARN); 2779228753Smm} 2780228753Smm 2781231200Smm/* 2782231200Smm * Note: Returns 0 on success, non-zero on failure. 2783228753Smm */ 2784228753Smmstatic int 2785228753Smmset_time(int fd, int mode, const char *name, 2786228753Smm time_t atime, long atime_nsec, 2787228753Smm time_t mtime, long mtime_nsec) 2788228753Smm{ 2789231200Smm /* Select the best implementation for this platform. */ 2790231200Smm#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS) 2791231200Smm /* 2792231200Smm * utimensat() and futimens() are defined in 2793231200Smm * POSIX.1-2008. They support ns resolution and setting times 2794231200Smm * on fds and symlinks. 2795231200Smm */ 2796228753Smm struct timespec ts[2]; 2797232153Smm (void)mode; /* UNUSED */ 2798228753Smm ts[0].tv_sec = atime; 2799228753Smm ts[0].tv_nsec = atime_nsec; 2800228753Smm ts[1].tv_sec = mtime; 2801228753Smm ts[1].tv_nsec = mtime_nsec; 2802228753Smm if (fd >= 0) 2803228753Smm return futimens(fd, ts); 2804228753Smm return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW); 2805231200Smm 2806228753Smm#elif HAVE_UTIMES 2807231200Smm /* 2808231200Smm * The utimes()-family functions support ��s-resolution and 2809231200Smm * setting times fds and symlinks. utimes() is documented as 2810231200Smm * LEGACY by POSIX, futimes() and lutimes() are not described 2811231200Smm * in POSIX. 2812231200Smm */ 2813228753Smm struct timeval times[2]; 2814228753Smm 2815228753Smm times[0].tv_sec = atime; 2816228753Smm times[0].tv_usec = atime_nsec / 1000; 2817228753Smm times[1].tv_sec = mtime; 2818228753Smm times[1].tv_usec = mtime_nsec / 1000; 2819228753Smm 2820228753Smm#ifdef HAVE_FUTIMES 2821228753Smm if (fd >= 0) 2822228753Smm return (futimes(fd, times)); 2823228753Smm#else 2824228753Smm (void)fd; /* UNUSED */ 2825228753Smm#endif 2826228753Smm#ifdef HAVE_LUTIMES 2827228753Smm (void)mode; /* UNUSED */ 2828228753Smm return (lutimes(name, times)); 2829228753Smm#else 2830228753Smm if (S_ISLNK(mode)) 2831228753Smm return (0); 2832228753Smm return (utimes(name, times)); 2833228753Smm#endif 2834231200Smm 2835228753Smm#elif defined(HAVE_UTIME) 2836231200Smm /* 2837231200Smm * utime() is POSIX-standard but only supports 1s resolution and 2838231200Smm * does not support fds or symlinks. 2839231200Smm */ 2840228753Smm struct utimbuf times; 2841228753Smm (void)fd; /* UNUSED */ 2842228753Smm (void)name; /* UNUSED */ 2843228753Smm (void)atime_nsec; /* UNUSED */ 2844228753Smm (void)mtime_nsec; /* UNUSED */ 2845228753Smm times.actime = atime; 2846228753Smm times.modtime = mtime; 2847228753Smm if (S_ISLNK(mode)) 2848228753Smm return (ARCHIVE_OK); 2849228753Smm return (utime(name, ×)); 2850231200Smm 2851231200Smm#else 2852231200Smm /* 2853231200Smm * We don't know how to set the time on this platform. 2854231200Smm */ 2855232153Smm (void)fd; /* UNUSED */ 2856232153Smm (void)mode; /* UNUSED */ 2857232153Smm (void)name; /* UNUSED */ 2858232153Smm (void)atime_nsec; /* UNUSED */ 2859232153Smm (void)mtime_nsec; /* UNUSED */ 2860231200Smm return (ARCHIVE_WARN); 2861231200Smm#endif 2862228753Smm} 2863231200Smm 2864231200Smm#ifdef F_SETTIMES /* Tru64 */ 2865228753Smmstatic int 2866231200Smmset_time_tru64(int fd, int mode, const char *name, 2867228753Smm time_t atime, long atime_nsec, 2868231200Smm time_t mtime, long mtime_nsec, 2869231200Smm time_t ctime, long ctime_nsec) 2870228753Smm{ 2871231200Smm struct attr_timbuf tstamp; 2872231200Smm struct timeval times[3]; 2873231200Smm times[0].tv_sec = atime; 2874231200Smm times[0].tv_usec = atime_nsec / 1000; 2875231200Smm times[1].tv_sec = mtime; 2876231200Smm times[1].tv_usec = mtime_nsec / 1000; 2877231200Smm times[2].tv_sec = ctime; 2878231200Smm times[2].tv_usec = ctime_nsec / 1000; 2879231200Smm tstamp.atime = times[0]; 2880231200Smm tstamp.mtime = times[1]; 2881231200Smm tstamp.ctime = times[2]; 2882231200Smm return (fcntl(fd,F_SETTIMES,&tstamp)); 2883228753Smm} 2884231200Smm#endif /* Tru64 */ 2885231200Smm 2886231200Smmstatic int 2887231200Smmset_times(struct archive_write_disk *a, 2888231200Smm int fd, int mode, const char *name, 2889231200Smm time_t atime, long atime_nanos, 2890231200Smm time_t birthtime, long birthtime_nanos, 2891231200Smm time_t mtime, long mtime_nanos, 2892232153Smm time_t cctime, long ctime_nanos) 2893231200Smm{ 2894231200Smm /* Note: set_time doesn't use libarchive return conventions! 2895231200Smm * It uses syscall conventions. So 0 here instead of ARCHIVE_OK. */ 2896231200Smm int r1 = 0, r2 = 0; 2897231200Smm 2898231200Smm#ifdef F_SETTIMES 2899231200Smm /* 2900231200Smm * on Tru64 try own fcntl first which can restore even the 2901231200Smm * ctime, fall back to default code path below if it fails 2902231200Smm * or if we are not running as root 2903231200Smm */ 2904231200Smm if (a->user_uid == 0 && 2905231200Smm set_time_tru64(fd, mode, name, 2906231200Smm atime, atime_nanos, mtime, 2907232153Smm mtime_nanos, cctime, ctime_nanos) == 0) { 2908231200Smm return (ARCHIVE_OK); 2909231200Smm } 2910232153Smm#else /* Tru64 */ 2911232153Smm (void)cctime; /* UNUSED */ 2912232153Smm (void)ctime_nanos; /* UNUSED */ 2913231200Smm#endif /* Tru64 */ 2914231200Smm 2915231200Smm#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME 2916231200Smm /* 2917231200Smm * If you have struct stat.st_birthtime, we assume BSD 2918231200Smm * birthtime semantics, in which {f,l,}utimes() updates 2919231200Smm * birthtime to earliest mtime. So we set the time twice, 2920231200Smm * first using the birthtime, then using the mtime. If 2921231200Smm * birthtime == mtime, this isn't necessary, so we skip it. 2922231200Smm * If birthtime > mtime, then this won't work, so we skip it. 2923231200Smm */ 2924231200Smm if (birthtime < mtime 2925231200Smm || (birthtime == mtime && birthtime_nanos < mtime_nanos)) 2926231200Smm r1 = set_time(fd, mode, name, 2927231200Smm atime, atime_nanos, 2928231200Smm birthtime, birthtime_nanos); 2929232153Smm#else 2930232153Smm (void)birthtime; /* UNUSED */ 2931232153Smm (void)birthtime_nanos; /* UNUSED */ 2932228753Smm#endif 2933231200Smm r2 = set_time(fd, mode, name, 2934231200Smm atime, atime_nanos, 2935231200Smm mtime, mtime_nanos); 2936231200Smm if (r1 != 0 || r2 != 0) { 2937231200Smm archive_set_error(&a->archive, errno, 2938231200Smm "Can't restore time"); 2939231200Smm return (ARCHIVE_WARN); 2940231200Smm } 2941231200Smm return (ARCHIVE_OK); 2942231200Smm} 2943228753Smm 2944228753Smmstatic int 2945231200Smmset_times_from_entry(struct archive_write_disk *a) 2946228753Smm{ 2947232153Smm time_t atime, birthtime, mtime, cctime; 2948231200Smm long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec; 2949228753Smm 2950231200Smm /* Suitable defaults. */ 2951232153Smm atime = birthtime = mtime = cctime = a->start_time; 2952231200Smm atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0; 2953231200Smm 2954228753Smm /* If no time was provided, we're done. */ 2955228753Smm if (!archive_entry_atime_is_set(a->entry) 2956228753Smm#if HAVE_STRUCT_STAT_ST_BIRTHTIME 2957228753Smm && !archive_entry_birthtime_is_set(a->entry) 2958228753Smm#endif 2959228753Smm && !archive_entry_mtime_is_set(a->entry)) 2960228753Smm return (ARCHIVE_OK); 2961228753Smm 2962228753Smm if (archive_entry_atime_is_set(a->entry)) { 2963228753Smm atime = archive_entry_atime(a->entry); 2964228753Smm atime_nsec = archive_entry_atime_nsec(a->entry); 2965228753Smm } 2966231200Smm if (archive_entry_birthtime_is_set(a->entry)) { 2967231200Smm birthtime = archive_entry_birthtime(a->entry); 2968231200Smm birthtime_nsec = archive_entry_birthtime_nsec(a->entry); 2969231200Smm } 2970228753Smm if (archive_entry_mtime_is_set(a->entry)) { 2971228753Smm mtime = archive_entry_mtime(a->entry); 2972228753Smm mtime_nsec = archive_entry_mtime_nsec(a->entry); 2973228753Smm } 2974231200Smm if (archive_entry_ctime_is_set(a->entry)) { 2975232153Smm cctime = archive_entry_ctime(a->entry); 2976231200Smm ctime_nsec = archive_entry_ctime_nsec(a->entry); 2977228753Smm } 2978228753Smm 2979231200Smm return set_times(a, a->fd, a->mode, a->name, 2980231200Smm atime, atime_nsec, 2981231200Smm birthtime, birthtime_nsec, 2982231200Smm mtime, mtime_nsec, 2983232153Smm cctime, ctime_nsec); 2984228753Smm} 2985228753Smm 2986228753Smmstatic int 2987228753Smmset_mode(struct archive_write_disk *a, int mode) 2988228753Smm{ 2989228753Smm int r = ARCHIVE_OK; 2990228753Smm mode &= 07777; /* Strip off file type bits. */ 2991228753Smm 2992228753Smm if (a->todo & TODO_SGID_CHECK) { 2993228753Smm /* 2994228753Smm * If we don't know the GID is right, we must stat() 2995228753Smm * to verify it. We can't just check the GID of this 2996228753Smm * process, since systems sometimes set GID from 2997228753Smm * the enclosing dir or based on ACLs. 2998228753Smm */ 2999231200Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 3000228753Smm return (r); 3001228753Smm if (a->pst->st_gid != a->gid) { 3002228753Smm mode &= ~ S_ISGID; 3003228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 3004228753Smm /* 3005228753Smm * This is only an error if you 3006228753Smm * requested owner restore. If you 3007228753Smm * didn't, we'll try to restore 3008228753Smm * sgid/suid, but won't consider it a 3009228753Smm * problem if we can't. 3010228753Smm */ 3011228753Smm archive_set_error(&a->archive, -1, 3012228753Smm "Can't restore SGID bit"); 3013228753Smm r = ARCHIVE_WARN; 3014228753Smm } 3015228753Smm } 3016228753Smm /* While we're here, double-check the UID. */ 3017228753Smm if (a->pst->st_uid != a->uid 3018228753Smm && (a->todo & TODO_SUID)) { 3019228753Smm mode &= ~ S_ISUID; 3020228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 3021228753Smm archive_set_error(&a->archive, -1, 3022228753Smm "Can't restore SUID bit"); 3023228753Smm r = ARCHIVE_WARN; 3024228753Smm } 3025228753Smm } 3026228753Smm a->todo &= ~TODO_SGID_CHECK; 3027228753Smm a->todo &= ~TODO_SUID_CHECK; 3028228753Smm } else if (a->todo & TODO_SUID_CHECK) { 3029228753Smm /* 3030228753Smm * If we don't know the UID is right, we can just check 3031228753Smm * the user, since all systems set the file UID from 3032228753Smm * the process UID. 3033228753Smm */ 3034228753Smm if (a->user_uid != a->uid) { 3035228753Smm mode &= ~ S_ISUID; 3036228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 3037228753Smm archive_set_error(&a->archive, -1, 3038228753Smm "Can't make file SUID"); 3039228753Smm r = ARCHIVE_WARN; 3040228753Smm } 3041228753Smm } 3042228753Smm a->todo &= ~TODO_SUID_CHECK; 3043228753Smm } 3044228753Smm 3045228753Smm if (S_ISLNK(a->mode)) { 3046228753Smm#ifdef HAVE_LCHMOD 3047228753Smm /* 3048228753Smm * If this is a symlink, use lchmod(). If the 3049228753Smm * platform doesn't support lchmod(), just skip it. A 3050228753Smm * platform that doesn't provide a way to set 3051228753Smm * permissions on symlinks probably ignores 3052228753Smm * permissions on symlinks, so a failure here has no 3053228753Smm * impact. 3054228753Smm */ 3055228753Smm if (lchmod(a->name, mode) != 0) { 3056228753Smm archive_set_error(&a->archive, errno, 3057228753Smm "Can't set permissions to 0%o", (int)mode); 3058228753Smm r = ARCHIVE_WARN; 3059228753Smm } 3060228753Smm#endif 3061228753Smm } else if (!S_ISDIR(a->mode)) { 3062228753Smm /* 3063228753Smm * If it's not a symlink and not a dir, then use 3064228753Smm * fchmod() or chmod(), depending on whether we have 3065228753Smm * an fd. Dirs get their perms set during the 3066228753Smm * post-extract fixup, which is handled elsewhere. 3067228753Smm */ 3068228753Smm#ifdef HAVE_FCHMOD 3069228753Smm if (a->fd >= 0) { 3070228753Smm if (fchmod(a->fd, mode) != 0) { 3071228753Smm archive_set_error(&a->archive, errno, 3072228753Smm "Can't set permissions to 0%o", (int)mode); 3073228753Smm r = ARCHIVE_WARN; 3074228753Smm } 3075228753Smm } else 3076228753Smm#endif 3077228753Smm /* If this platform lacks fchmod(), then 3078228753Smm * we'll just use chmod(). */ 3079228753Smm if (chmod(a->name, mode) != 0) { 3080228753Smm archive_set_error(&a->archive, errno, 3081228753Smm "Can't set permissions to 0%o", (int)mode); 3082228753Smm r = ARCHIVE_WARN; 3083228753Smm } 3084228753Smm } 3085228753Smm return (r); 3086228753Smm} 3087228753Smm 3088228753Smmstatic int 3089228753Smmset_fflags(struct archive_write_disk *a) 3090228753Smm{ 3091228753Smm struct fixup_entry *le; 3092228753Smm unsigned long set, clear; 3093228753Smm int r; 3094228753Smm int critical_flags; 3095228753Smm mode_t mode = archive_entry_mode(a->entry); 3096228753Smm 3097228753Smm /* 3098228753Smm * Make 'critical_flags' hold all file flags that can't be 3099228753Smm * immediately restored. For example, on BSD systems, 3100228753Smm * SF_IMMUTABLE prevents hardlinks from being created, so 3101228753Smm * should not be set until after any hardlinks are created. To 3102228753Smm * preserve some semblance of portability, this uses #ifdef 3103228753Smm * extensively. Ugly, but it works. 3104228753Smm * 3105228753Smm * Yes, Virginia, this does create a security race. It's mitigated 3106228753Smm * somewhat by the practice of creating dirs 0700 until the extract 3107228753Smm * is done, but it would be nice if we could do more than that. 3108228753Smm * People restoring critical file systems should be wary of 3109228753Smm * other programs that might try to muck with files as they're 3110228753Smm * being restored. 3111228753Smm */ 3112228753Smm /* Hopefully, the compiler will optimize this mess into a constant. */ 3113228753Smm critical_flags = 0; 3114228753Smm#ifdef SF_IMMUTABLE 3115228753Smm critical_flags |= SF_IMMUTABLE; 3116228753Smm#endif 3117228753Smm#ifdef UF_IMMUTABLE 3118228753Smm critical_flags |= UF_IMMUTABLE; 3119228753Smm#endif 3120228753Smm#ifdef SF_APPEND 3121228753Smm critical_flags |= SF_APPEND; 3122228753Smm#endif 3123228753Smm#ifdef UF_APPEND 3124228753Smm critical_flags |= UF_APPEND; 3125228753Smm#endif 3126228753Smm#ifdef EXT2_APPEND_FL 3127228753Smm critical_flags |= EXT2_APPEND_FL; 3128228753Smm#endif 3129228753Smm#ifdef EXT2_IMMUTABLE_FL 3130228753Smm critical_flags |= EXT2_IMMUTABLE_FL; 3131228753Smm#endif 3132228753Smm 3133228753Smm if (a->todo & TODO_FFLAGS) { 3134228753Smm archive_entry_fflags(a->entry, &set, &clear); 3135228753Smm 3136228753Smm /* 3137228753Smm * The first test encourages the compiler to eliminate 3138228753Smm * all of this if it's not necessary. 3139228753Smm */ 3140228753Smm if ((critical_flags != 0) && (set & critical_flags)) { 3141228753Smm le = current_fixup(a, a->name); 3142248616Smm if (le == NULL) 3143248616Smm return (ARCHIVE_FATAL); 3144228753Smm le->fixup |= TODO_FFLAGS; 3145228753Smm le->fflags_set = set; 3146228753Smm /* Store the mode if it's not already there. */ 3147228753Smm if ((le->fixup & TODO_MODE) == 0) 3148228753Smm le->mode = mode; 3149228753Smm } else { 3150228753Smm r = set_fflags_platform(a, a->fd, 3151228753Smm a->name, mode, set, clear); 3152228753Smm if (r != ARCHIVE_OK) 3153228753Smm return (r); 3154228753Smm } 3155228753Smm } 3156228753Smm return (ARCHIVE_OK); 3157228753Smm} 3158228753Smm 3159228753Smm 3160228753Smm#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS) 3161228753Smm/* 3162228753Smm * BSD reads flags using stat() and sets them with one of {f,l,}chflags() 3163228753Smm */ 3164228753Smmstatic int 3165228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 3166228753Smm mode_t mode, unsigned long set, unsigned long clear) 3167228753Smm{ 3168228753Smm int r; 3169228753Smm 3170228753Smm (void)mode; /* UNUSED */ 3171228753Smm if (set == 0 && clear == 0) 3172228753Smm return (ARCHIVE_OK); 3173228753Smm 3174228753Smm /* 3175228753Smm * XXX Is the stat here really necessary? Or can I just use 3176228753Smm * the 'set' flags directly? In particular, I'm not sure 3177228753Smm * about the correct approach if we're overwriting an existing 3178228753Smm * file that already has flags on it. XXX 3179228753Smm */ 3180231200Smm if ((r = lazy_stat(a)) != ARCHIVE_OK) 3181228753Smm return (r); 3182228753Smm 3183228753Smm a->st.st_flags &= ~clear; 3184228753Smm a->st.st_flags |= set; 3185228753Smm#ifdef HAVE_FCHFLAGS 3186228753Smm /* If platform has fchflags() and we were given an fd, use it. */ 3187228753Smm if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0) 3188228753Smm return (ARCHIVE_OK); 3189228753Smm#endif 3190228753Smm /* 3191228753Smm * If we can't use the fd to set the flags, we'll use the 3192228753Smm * pathname to set flags. We prefer lchflags() but will use 3193228753Smm * chflags() if we must. 3194228753Smm */ 3195228753Smm#ifdef HAVE_LCHFLAGS 3196228753Smm if (lchflags(name, a->st.st_flags) == 0) 3197228753Smm return (ARCHIVE_OK); 3198228753Smm#elif defined(HAVE_CHFLAGS) 3199228753Smm if (S_ISLNK(a->st.st_mode)) { 3200228753Smm archive_set_error(&a->archive, errno, 3201228753Smm "Can't set file flags on symlink."); 3202228753Smm return (ARCHIVE_WARN); 3203228753Smm } 3204228753Smm if (chflags(name, a->st.st_flags) == 0) 3205228753Smm return (ARCHIVE_OK); 3206228753Smm#endif 3207228753Smm archive_set_error(&a->archive, errno, 3208228753Smm "Failed to set file flags"); 3209228753Smm return (ARCHIVE_WARN); 3210228753Smm} 3211228753Smm 3212231200Smm#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) 3213228753Smm/* 3214228753Smm * Linux uses ioctl() to read and write file flags. 3215228753Smm */ 3216228753Smmstatic int 3217228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 3218228753Smm mode_t mode, unsigned long set, unsigned long clear) 3219228753Smm{ 3220228753Smm int ret; 3221228753Smm int myfd = fd; 3222248616Smm int newflags, oldflags; 3223248616Smm int sf_mask = 0; 3224228753Smm 3225228753Smm if (set == 0 && clear == 0) 3226228753Smm return (ARCHIVE_OK); 3227228753Smm /* Only regular files and dirs can have flags. */ 3228228753Smm if (!S_ISREG(mode) && !S_ISDIR(mode)) 3229228753Smm return (ARCHIVE_OK); 3230228753Smm 3231228753Smm /* If we weren't given an fd, open it ourselves. */ 3232248616Smm if (myfd < 0) { 3233248616Smm myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC); 3234248616Smm __archive_ensure_cloexec_flag(myfd); 3235248616Smm } 3236228753Smm if (myfd < 0) 3237228753Smm return (ARCHIVE_OK); 3238228753Smm 3239228753Smm /* 3240228753Smm * Linux has no define for the flags that are only settable by 3241228753Smm * the root user. This code may seem a little complex, but 3242228753Smm * there seem to be some Linux systems that lack these 3243228753Smm * defines. (?) The code below degrades reasonably gracefully 3244228753Smm * if sf_mask is incomplete. 3245228753Smm */ 3246228753Smm#ifdef EXT2_IMMUTABLE_FL 3247228753Smm sf_mask |= EXT2_IMMUTABLE_FL; 3248228753Smm#endif 3249228753Smm#ifdef EXT2_APPEND_FL 3250228753Smm sf_mask |= EXT2_APPEND_FL; 3251228753Smm#endif 3252228753Smm /* 3253228753Smm * XXX As above, this would be way simpler if we didn't have 3254228753Smm * to read the current flags from disk. XXX 3255228753Smm */ 3256228753Smm ret = ARCHIVE_OK; 3257231200Smm 3258231200Smm /* Read the current file flags. */ 3259231200Smm if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) < 0) 3260231200Smm goto fail; 3261231200Smm 3262228753Smm /* Try setting the flags as given. */ 3263231200Smm newflags = (oldflags & ~clear) | set; 3264231200Smm if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0) 3265231200Smm goto cleanup; 3266231200Smm if (errno != EPERM) 3267231200Smm goto fail; 3268231200Smm 3269228753Smm /* If we couldn't set all the flags, try again with a subset. */ 3270231200Smm newflags &= ~sf_mask; 3271231200Smm oldflags &= sf_mask; 3272231200Smm newflags |= oldflags; 3273231200Smm if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0) 3274231200Smm goto cleanup; 3275231200Smm 3276228753Smm /* We couldn't set the flags, so report the failure. */ 3277228753Smmfail: 3278228753Smm archive_set_error(&a->archive, errno, 3279228753Smm "Failed to set file flags"); 3280228753Smm ret = ARCHIVE_WARN; 3281228753Smmcleanup: 3282228753Smm if (fd < 0) 3283228753Smm close(myfd); 3284228753Smm return (ret); 3285228753Smm} 3286228753Smm 3287228753Smm#else 3288228753Smm 3289228753Smm/* 3290228753Smm * Of course, some systems have neither BSD chflags() nor Linux' flags 3291228753Smm * support through ioctl(). 3292228753Smm */ 3293228753Smmstatic int 3294228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 3295228753Smm mode_t mode, unsigned long set, unsigned long clear) 3296228753Smm{ 3297228753Smm (void)a; /* UNUSED */ 3298228753Smm (void)fd; /* UNUSED */ 3299228753Smm (void)name; /* UNUSED */ 3300228753Smm (void)mode; /* UNUSED */ 3301228753Smm (void)set; /* UNUSED */ 3302228753Smm (void)clear; /* UNUSED */ 3303228753Smm return (ARCHIVE_OK); 3304228753Smm} 3305228753Smm 3306228753Smm#endif /* __linux */ 3307228753Smm 3308231200Smm#ifndef HAVE_COPYFILE_H 3309231200Smm/* Default is to simply drop Mac extended metadata. */ 3310231200Smmstatic int 3311231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname, 3312231200Smm const void *metadata, size_t metadata_size) 3313231200Smm{ 3314231200Smm (void)a; /* UNUSED */ 3315231200Smm (void)pathname; /* UNUSED */ 3316231200Smm (void)metadata; /* UNUSED */ 3317231200Smm (void)metadata_size; /* UNUSED */ 3318231200Smm return (ARCHIVE_OK); 3319231200Smm} 3320248616Smm 3321248616Smmstatic int 3322248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname) 3323248616Smm{ 3324248616Smm (void)a; /* UNUSED */ 3325248616Smm (void)pathname; /* UNUSED */ 3326248616Smm return (ARCHIVE_OK); 3327248616Smm} 3328231200Smm#else 3329231200Smm 3330231200Smm/* 3331231200Smm * On Mac OS, we use copyfile() to unpack the metadata and 3332231200Smm * apply it to the target file. 3333231200Smm */ 3334248616Smm 3335248616Smm#if defined(HAVE_SYS_XATTR_H) 3336231200Smmstatic int 3337248616Smmcopy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd) 3338248616Smm{ 3339248616Smm ssize_t xattr_size; 3340248616Smm char *xattr_names = NULL, *xattr_val = NULL; 3341248616Smm int ret = ARCHIVE_OK, xattr_i; 3342248616Smm 3343248616Smm xattr_size = flistxattr(tmpfd, NULL, 0, 0); 3344248616Smm if (xattr_size == -1) { 3345248616Smm archive_set_error(&a->archive, errno, 3346248616Smm "Failed to read metadata(xattr)"); 3347248616Smm ret = ARCHIVE_WARN; 3348248616Smm goto exit_xattr; 3349248616Smm } 3350248616Smm xattr_names = malloc(xattr_size); 3351248616Smm if (xattr_names == NULL) { 3352248616Smm archive_set_error(&a->archive, ENOMEM, 3353248616Smm "Can't allocate memory for metadata(xattr)"); 3354248616Smm ret = ARCHIVE_FATAL; 3355248616Smm goto exit_xattr; 3356248616Smm } 3357248616Smm xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0); 3358248616Smm if (xattr_size == -1) { 3359248616Smm archive_set_error(&a->archive, errno, 3360248616Smm "Failed to read metadata(xattr)"); 3361248616Smm ret = ARCHIVE_WARN; 3362248616Smm goto exit_xattr; 3363248616Smm } 3364248616Smm for (xattr_i = 0; xattr_i < xattr_size; 3365248616Smm xattr_i += strlen(xattr_names + xattr_i) + 1) { 3366248616Smm ssize_t s; 3367248616Smm int f; 3368248616Smm 3369248616Smm s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0); 3370248616Smm if (s == -1) { 3371248616Smm archive_set_error(&a->archive, errno, 3372248616Smm "Failed to get metadata(xattr)"); 3373248616Smm ret = ARCHIVE_WARN; 3374248616Smm goto exit_xattr; 3375248616Smm } 3376248616Smm xattr_val = realloc(xattr_val, s); 3377248616Smm if (xattr_val == NULL) { 3378248616Smm archive_set_error(&a->archive, ENOMEM, 3379248616Smm "Failed to get metadata(xattr)"); 3380248616Smm ret = ARCHIVE_WARN; 3381248616Smm goto exit_xattr; 3382248616Smm } 3383248616Smm s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0); 3384248616Smm if (s == -1) { 3385248616Smm archive_set_error(&a->archive, errno, 3386248616Smm "Failed to get metadata(xattr)"); 3387248616Smm ret = ARCHIVE_WARN; 3388248616Smm goto exit_xattr; 3389248616Smm } 3390248616Smm f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0); 3391248616Smm if (f == -1) { 3392248616Smm archive_set_error(&a->archive, errno, 3393248616Smm "Failed to get metadata(xattr)"); 3394248616Smm ret = ARCHIVE_WARN; 3395248616Smm goto exit_xattr; 3396248616Smm } 3397248616Smm } 3398248616Smmexit_xattr: 3399248616Smm free(xattr_names); 3400248616Smm free(xattr_val); 3401248616Smm return (ret); 3402248616Smm} 3403248616Smm#endif 3404248616Smm 3405248616Smmstatic int 3406248616Smmcopy_acls(struct archive_write_disk *a, int tmpfd, int dffd) 3407248616Smm{ 3408248616Smm acl_t acl, dfacl = NULL; 3409248616Smm int acl_r, ret = ARCHIVE_OK; 3410248616Smm 3411248616Smm acl = acl_get_fd(tmpfd); 3412248616Smm if (acl == NULL) { 3413248616Smm if (errno == ENOENT) 3414248616Smm /* There are not any ACLs. */ 3415248616Smm return (ret); 3416248616Smm archive_set_error(&a->archive, errno, 3417248616Smm "Failed to get metadata(acl)"); 3418248616Smm ret = ARCHIVE_WARN; 3419248616Smm goto exit_acl; 3420248616Smm } 3421248616Smm dfacl = acl_dup(acl); 3422248616Smm acl_r = acl_set_fd(dffd, dfacl); 3423248616Smm if (acl_r == -1) { 3424248616Smm archive_set_error(&a->archive, errno, 3425248616Smm "Failed to get metadata(acl)"); 3426248616Smm ret = ARCHIVE_WARN; 3427248616Smm goto exit_acl; 3428248616Smm } 3429248616Smmexit_acl: 3430248616Smm if (acl) 3431248616Smm acl_free(acl); 3432248616Smm if (dfacl) 3433248616Smm acl_free(dfacl); 3434248616Smm return (ret); 3435248616Smm} 3436248616Smm 3437248616Smmstatic int 3438248616Smmcreate_tempdatafork(struct archive_write_disk *a, const char *pathname) 3439248616Smm{ 3440248616Smm struct archive_string tmpdatafork; 3441248616Smm int tmpfd; 3442248616Smm 3443248616Smm archive_string_init(&tmpdatafork); 3444248616Smm archive_strcpy(&tmpdatafork, "tar.md.XXXXXX"); 3445248616Smm tmpfd = mkstemp(tmpdatafork.s); 3446248616Smm if (tmpfd < 0) { 3447248616Smm archive_set_error(&a->archive, errno, 3448248616Smm "Failed to mkstemp"); 3449248616Smm archive_string_free(&tmpdatafork); 3450248616Smm return (-1); 3451248616Smm } 3452248616Smm if (copyfile(pathname, tmpdatafork.s, 0, 3453248616Smm COPYFILE_UNPACK | COPYFILE_NOFOLLOW 3454248616Smm | COPYFILE_ACL | COPYFILE_XATTR) < 0) { 3455248616Smm archive_set_error(&a->archive, errno, 3456248616Smm "Failed to restore metadata"); 3457248616Smm close(tmpfd); 3458248616Smm tmpfd = -1; 3459248616Smm } 3460248616Smm unlink(tmpdatafork.s); 3461248616Smm archive_string_free(&tmpdatafork); 3462248616Smm return (tmpfd); 3463248616Smm} 3464248616Smm 3465248616Smmstatic int 3466248616Smmcopy_metadata(struct archive_write_disk *a, const char *metadata, 3467248616Smm const char *datafork, int datafork_compressed) 3468248616Smm{ 3469248616Smm int ret = ARCHIVE_OK; 3470248616Smm 3471248616Smm if (datafork_compressed) { 3472248616Smm int dffd, tmpfd; 3473248616Smm 3474248616Smm tmpfd = create_tempdatafork(a, metadata); 3475248616Smm if (tmpfd == -1) 3476248616Smm return (ARCHIVE_WARN); 3477248616Smm 3478248616Smm /* 3479248616Smm * Do not open the data fork compressed by HFS+ compression 3480248616Smm * with at least a writing mode(O_RDWR or O_WRONLY). it 3481248616Smm * makes the data fork uncompressed. 3482248616Smm */ 3483248616Smm dffd = open(datafork, 0); 3484248616Smm if (dffd == -1) { 3485248616Smm archive_set_error(&a->archive, errno, 3486248616Smm "Failed to open the data fork for metadata"); 3487248616Smm close(tmpfd); 3488248616Smm return (ARCHIVE_WARN); 3489248616Smm } 3490248616Smm 3491248616Smm#if defined(HAVE_SYS_XATTR_H) 3492248616Smm ret = copy_xattrs(a, tmpfd, dffd); 3493248616Smm if (ret == ARCHIVE_OK) 3494248616Smm#endif 3495248616Smm ret = copy_acls(a, tmpfd, dffd); 3496248616Smm close(tmpfd); 3497248616Smm close(dffd); 3498248616Smm } else { 3499248616Smm if (copyfile(metadata, datafork, 0, 3500248616Smm COPYFILE_UNPACK | COPYFILE_NOFOLLOW 3501248616Smm | COPYFILE_ACL | COPYFILE_XATTR) < 0) { 3502248616Smm archive_set_error(&a->archive, errno, 3503248616Smm "Failed to restore metadata"); 3504248616Smm ret = ARCHIVE_WARN; 3505248616Smm } 3506248616Smm } 3507248616Smm return (ret); 3508248616Smm} 3509248616Smm 3510248616Smmstatic int 3511231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname, 3512231200Smm const void *metadata, size_t metadata_size) 3513231200Smm{ 3514231200Smm struct archive_string tmp; 3515231200Smm ssize_t written; 3516231200Smm int fd; 3517231200Smm int ret = ARCHIVE_OK; 3518231200Smm 3519231200Smm /* This would be simpler if copyfile() could just accept the 3520231200Smm * metadata as a block of memory; then we could sidestep this 3521231200Smm * silly dance of writing the data to disk just so that 3522231200Smm * copyfile() can read it back in again. */ 3523231200Smm archive_string_init(&tmp); 3524231200Smm archive_strcpy(&tmp, pathname); 3525231200Smm archive_strcat(&tmp, ".XXXXXX"); 3526231200Smm fd = mkstemp(tmp.s); 3527231200Smm 3528231200Smm if (fd < 0) { 3529231200Smm archive_set_error(&a->archive, errno, 3530231200Smm "Failed to restore metadata"); 3531248616Smm archive_string_free(&tmp); 3532231200Smm return (ARCHIVE_WARN); 3533231200Smm } 3534231200Smm written = write(fd, metadata, metadata_size); 3535231200Smm close(fd); 3536248616Smm if ((size_t)written != metadata_size) { 3537231200Smm archive_set_error(&a->archive, errno, 3538231200Smm "Failed to restore metadata"); 3539231200Smm ret = ARCHIVE_WARN; 3540248616Smm } else { 3541248616Smm int compressed; 3542248616Smm 3543248616Smm#if defined(UF_COMPRESSED) 3544248616Smm if ((a->todo & TODO_HFS_COMPRESSION) != 0 && 3545248616Smm (ret = lazy_stat(a)) == ARCHIVE_OK) 3546248616Smm compressed = a->st.st_flags & UF_COMPRESSED; 3547248616Smm else 3548248616Smm#endif 3549248616Smm compressed = 0; 3550248616Smm ret = copy_metadata(a, tmp.s, pathname, compressed); 3551231200Smm } 3552231200Smm unlink(tmp.s); 3553248616Smm archive_string_free(&tmp); 3554231200Smm return (ret); 3555231200Smm} 3556248616Smm 3557248616Smmstatic int 3558248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname) 3559248616Smm{ 3560248616Smm char buff[8]; 3561248616Smm struct stat st; 3562248616Smm const char *p; 3563248616Smm struct archive_string datafork; 3564248616Smm int fd = -1, ret = ARCHIVE_OK; 3565248616Smm 3566248616Smm archive_string_init(&datafork); 3567248616Smm /* Check if the current file name is a type of the resource 3568248616Smm * fork file. */ 3569248616Smm p = strrchr(pathname, '/'); 3570248616Smm if (p == NULL) 3571248616Smm p = pathname; 3572248616Smm else 3573248616Smm p++; 3574248616Smm if (p[0] != '.' || p[1] != '_') 3575248616Smm goto skip_appledouble; 3576248616Smm 3577248616Smm /* 3578248616Smm * Check if the data fork file exists. 3579248616Smm * 3580248616Smm * TODO: Check if this write disk object has handled it. 3581248616Smm */ 3582248616Smm archive_strncpy(&datafork, pathname, p - pathname); 3583248616Smm archive_strcat(&datafork, p + 2); 3584248616Smm if (lstat(datafork.s, &st) == -1 || 3585248616Smm (st.st_mode & AE_IFMT) != AE_IFREG) 3586248616Smm goto skip_appledouble; 3587248616Smm 3588248616Smm /* 3589248616Smm * Check if the file is in the AppleDouble form. 3590248616Smm */ 3591248616Smm fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC); 3592248616Smm __archive_ensure_cloexec_flag(fd); 3593248616Smm if (fd == -1) { 3594248616Smm archive_set_error(&a->archive, errno, 3595248616Smm "Failed to open a restoring file"); 3596248616Smm ret = ARCHIVE_WARN; 3597248616Smm goto skip_appledouble; 3598248616Smm } 3599248616Smm if (read(fd, buff, 8) == -1) { 3600248616Smm archive_set_error(&a->archive, errno, 3601248616Smm "Failed to read a restoring file"); 3602248616Smm close(fd); 3603248616Smm ret = ARCHIVE_WARN; 3604248616Smm goto skip_appledouble; 3605248616Smm } 3606248616Smm close(fd); 3607248616Smm /* Check AppleDouble Magic Code. */ 3608248616Smm if (archive_be32dec(buff) != 0x00051607) 3609248616Smm goto skip_appledouble; 3610248616Smm /* Check AppleDouble Version. */ 3611248616Smm if (archive_be32dec(buff+4) != 0x00020000) 3612248616Smm goto skip_appledouble; 3613248616Smm 3614248616Smm ret = copy_metadata(a, pathname, datafork.s, 3615248616Smm#if defined(UF_COMPRESSED) 3616248616Smm st.st_flags & UF_COMPRESSED); 3617248616Smm#else 3618248616Smm 0); 3619231200Smm#endif 3620248616Smm if (ret == ARCHIVE_OK) { 3621248616Smm unlink(pathname); 3622248616Smm ret = ARCHIVE_EOF; 3623248616Smm } 3624248616Smmskip_appledouble: 3625248616Smm archive_string_free(&datafork); 3626248616Smm return (ret); 3627248616Smm} 3628248616Smm#endif 3629231200Smm 3630231200Smm#if HAVE_LSETXATTR || HAVE_LSETEA 3631228753Smm/* 3632231200Smm * Restore extended attributes - Linux and AIX implementations: 3633231200Smm * AIX' ea interface is syntaxwise identical to the Linux xattr interface. 3634228753Smm */ 3635228753Smmstatic int 3636228753Smmset_xattrs(struct archive_write_disk *a) 3637228753Smm{ 3638228753Smm struct archive_entry *entry = a->entry; 3639228753Smm static int warning_done = 0; 3640228753Smm int ret = ARCHIVE_OK; 3641228753Smm int i = archive_entry_xattr_reset(entry); 3642228753Smm 3643228753Smm while (i--) { 3644228753Smm const char *name; 3645228753Smm const void *value; 3646228753Smm size_t size; 3647228753Smm archive_entry_xattr_next(entry, &name, &value, &size); 3648228753Smm if (name != NULL && 3649228753Smm strncmp(name, "xfsroot.", 8) != 0 && 3650228753Smm strncmp(name, "system.", 7) != 0) { 3651228753Smm int e; 3652228753Smm#if HAVE_FSETXATTR 3653228753Smm if (a->fd >= 0) 3654228753Smm e = fsetxattr(a->fd, name, value, size, 0); 3655228753Smm else 3656231200Smm#elif HAVE_FSETEA 3657231200Smm if (a->fd >= 0) 3658231200Smm e = fsetea(a->fd, name, value, size, 0); 3659231200Smm else 3660228753Smm#endif 3661228753Smm { 3662231200Smm#if HAVE_LSETXATTR 3663228753Smm e = lsetxattr(archive_entry_pathname(entry), 3664228753Smm name, value, size, 0); 3665231200Smm#elif HAVE_LSETEA 3666231200Smm e = lsetea(archive_entry_pathname(entry), 3667231200Smm name, value, size, 0); 3668231200Smm#endif 3669228753Smm } 3670228753Smm if (e == -1) { 3671231200Smm if (errno == ENOTSUP || errno == ENOSYS) { 3672228753Smm if (!warning_done) { 3673228753Smm warning_done = 1; 3674228753Smm archive_set_error(&a->archive, errno, 3675228753Smm "Cannot restore extended " 3676228753Smm "attributes on this file " 3677228753Smm "system"); 3678228753Smm } 3679228753Smm } else 3680228753Smm archive_set_error(&a->archive, errno, 3681228753Smm "Failed to set extended attribute"); 3682228753Smm ret = ARCHIVE_WARN; 3683228753Smm } 3684228753Smm } else { 3685228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 3686228753Smm "Invalid extended attribute encountered"); 3687228753Smm ret = ARCHIVE_WARN; 3688228753Smm } 3689228753Smm } 3690228753Smm return (ret); 3691228753Smm} 3692228753Smm#elif HAVE_EXTATTR_SET_FILE && HAVE_DECL_EXTATTR_NAMESPACE_USER 3693228753Smm/* 3694228753Smm * Restore extended attributes - FreeBSD implementation 3695228753Smm */ 3696228753Smmstatic int 3697228753Smmset_xattrs(struct archive_write_disk *a) 3698228753Smm{ 3699228753Smm struct archive_entry *entry = a->entry; 3700228753Smm static int warning_done = 0; 3701228753Smm int ret = ARCHIVE_OK; 3702228753Smm int i = archive_entry_xattr_reset(entry); 3703228753Smm 3704228753Smm while (i--) { 3705228753Smm const char *name; 3706228753Smm const void *value; 3707228753Smm size_t size; 3708228753Smm archive_entry_xattr_next(entry, &name, &value, &size); 3709228753Smm if (name != NULL) { 3710248995Smdf ssize_t e; 3711228753Smm int namespace; 3712228753Smm 3713228753Smm if (strncmp(name, "user.", 5) == 0) { 3714228753Smm /* "user." attributes go to user namespace */ 3715228753Smm name += 5; 3716228753Smm namespace = EXTATTR_NAMESPACE_USER; 3717228753Smm } else { 3718228753Smm /* Warn about other extended attributes. */ 3719228753Smm archive_set_error(&a->archive, 3720228753Smm ARCHIVE_ERRNO_FILE_FORMAT, 3721228753Smm "Can't restore extended attribute ``%s''", 3722228753Smm name); 3723228753Smm ret = ARCHIVE_WARN; 3724228753Smm continue; 3725228753Smm } 3726228753Smm errno = 0; 3727228753Smm#if HAVE_EXTATTR_SET_FD 3728228753Smm if (a->fd >= 0) 3729228753Smm e = extattr_set_fd(a->fd, namespace, name, value, size); 3730228753Smm else 3731228753Smm#endif 3732228753Smm /* TODO: should we use extattr_set_link() instead? */ 3733228753Smm { 3734228753Smm e = extattr_set_file(archive_entry_pathname(entry), 3735228753Smm namespace, name, value, size); 3736228753Smm } 3737248995Smdf if (e != (ssize_t)size) { 3738231200Smm if (errno == ENOTSUP || errno == ENOSYS) { 3739228753Smm if (!warning_done) { 3740228753Smm warning_done = 1; 3741228753Smm archive_set_error(&a->archive, errno, 3742228753Smm "Cannot restore extended " 3743228753Smm "attributes on this file " 3744228753Smm "system"); 3745228753Smm } 3746228753Smm } else { 3747228753Smm archive_set_error(&a->archive, errno, 3748228753Smm "Failed to set extended attribute"); 3749228753Smm } 3750228753Smm 3751228753Smm ret = ARCHIVE_WARN; 3752228753Smm } 3753228753Smm } 3754228753Smm } 3755228753Smm return (ret); 3756228753Smm} 3757228753Smm#else 3758228753Smm/* 3759228753Smm * Restore extended attributes - stub implementation for unsupported systems 3760228753Smm */ 3761228753Smmstatic int 3762228753Smmset_xattrs(struct archive_write_disk *a) 3763228753Smm{ 3764228753Smm static int warning_done = 0; 3765228753Smm 3766228753Smm /* If there aren't any extended attributes, then it's okay not 3767228753Smm * to extract them, otherwise, issue a single warning. */ 3768228753Smm if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) { 3769228753Smm warning_done = 1; 3770228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 3771228753Smm "Cannot restore extended attributes on this system"); 3772228753Smm return (ARCHIVE_WARN); 3773228753Smm } 3774228753Smm /* Warning was already emitted; suppress further warnings. */ 3775228753Smm return (ARCHIVE_OK); 3776228753Smm} 3777228753Smm#endif 3778228753Smm 3779228753Smm/* 3780228753Smm * Test if file on disk is older than entry. 3781228753Smm */ 3782228753Smmstatic int 3783228753Smmolder(struct stat *st, struct archive_entry *entry) 3784228753Smm{ 3785228753Smm /* First, test the seconds and return if we have a definite answer. */ 3786228753Smm /* Definitely older. */ 3787228753Smm if (st->st_mtime < archive_entry_mtime(entry)) 3788228753Smm return (1); 3789228753Smm /* Definitely younger. */ 3790228753Smm if (st->st_mtime > archive_entry_mtime(entry)) 3791228753Smm return (0); 3792228753Smm /* If this platform supports fractional seconds, try those. */ 3793228753Smm#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 3794228753Smm /* Definitely older. */ 3795228753Smm if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry)) 3796228753Smm return (1); 3797228753Smm#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 3798228753Smm /* Definitely older. */ 3799228753Smm if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry)) 3800228753Smm return (1); 3801228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_N 3802228753Smm /* older. */ 3803228753Smm if (st->st_mtime_n < archive_entry_mtime_nsec(entry)) 3804228753Smm return (1); 3805228753Smm#elif HAVE_STRUCT_STAT_ST_UMTIME 3806228753Smm /* older. */ 3807228753Smm if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry)) 3808228753Smm return (1); 3809228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_USEC 3810228753Smm /* older. */ 3811228753Smm if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry)) 3812228753Smm return (1); 3813228753Smm#else 3814228753Smm /* This system doesn't have high-res timestamps. */ 3815228753Smm#endif 3816228753Smm /* Same age or newer, so not older. */ 3817228753Smm return (0); 3818228753Smm} 3819231200Smm 3820231200Smm#endif /* !_WIN32 || __CYGWIN__ */ 3821231200Smm 3822