1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer 10228753Smm * in this position and unchanged. 11228753Smm * 2. Redistributions in binary form must reproduce the above copyright 12228753Smm * notice, this list of conditions and the following disclaimer in the 13228753Smm * documentation and/or other materials provided with the distribution. 14228753Smm * 15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25228753Smm */ 26228753Smm 27228753Smm#include "archive_platform.h" 28229592Smm__FBSDID("$FreeBSD$"); 29228753Smm 30228753Smm#ifdef HAVE_SYS_TYPES_H 31228753Smm#include <sys/types.h> 32228753Smm#endif 33228753Smm#ifdef HAVE_SYS_ACL_H 34228753Smm#include <sys/acl.h> 35228753Smm#endif 36228753Smm#ifdef HAVE_SYS_EXTATTR_H 37228753Smm#include <sys/extattr.h> 38228753Smm#endif 39228753Smm#ifdef HAVE_SYS_XATTR_H 40228753Smm#include <sys/xattr.h> 41228753Smm#endif 42228753Smm#ifdef HAVE_ATTR_XATTR_H 43228753Smm#include <attr/xattr.h> 44228753Smm#endif 45228753Smm#ifdef HAVE_SYS_IOCTL_H 46228753Smm#include <sys/ioctl.h> 47228753Smm#endif 48228753Smm#ifdef HAVE_SYS_STAT_H 49228753Smm#include <sys/stat.h> 50228753Smm#endif 51228753Smm#ifdef HAVE_SYS_TIME_H 52228753Smm#include <sys/time.h> 53228753Smm#endif 54228753Smm#ifdef HAVE_SYS_UTIME_H 55228753Smm#include <sys/utime.h> 56228753Smm#endif 57228753Smm#ifdef HAVE_ERRNO_H 58228753Smm#include <errno.h> 59228753Smm#endif 60228753Smm#ifdef HAVE_FCNTL_H 61228753Smm#include <fcntl.h> 62228753Smm#endif 63228753Smm#ifdef HAVE_GRP_H 64228753Smm#include <grp.h> 65228753Smm#endif 66228753Smm#ifdef HAVE_LINUX_FS_H 67228753Smm#include <linux/fs.h> /* for Linux file flags */ 68228753Smm#endif 69228753Smm/* 70228753Smm * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 71228753Smm * As the include guards don't agree, the order of include is important. 72228753Smm */ 73228753Smm#ifdef HAVE_LINUX_EXT2_FS_H 74228753Smm#include <linux/ext2_fs.h> /* for Linux file flags */ 75228753Smm#endif 76228753Smm#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 77228753Smm#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ 78228753Smm#endif 79228753Smm#ifdef HAVE_LIMITS_H 80228753Smm#include <limits.h> 81228753Smm#endif 82228753Smm#ifdef HAVE_PWD_H 83228753Smm#include <pwd.h> 84228753Smm#endif 85228753Smm#include <stdio.h> 86228753Smm#ifdef HAVE_STDLIB_H 87228753Smm#include <stdlib.h> 88228753Smm#endif 89228753Smm#ifdef HAVE_STRING_H 90228753Smm#include <string.h> 91228753Smm#endif 92228753Smm#ifdef HAVE_UNISTD_H 93228753Smm#include <unistd.h> 94228753Smm#endif 95228753Smm#ifdef HAVE_UTIME_H 96228753Smm#include <utime.h> 97228753Smm#endif 98228753Smm 99228753Smm#include "archive.h" 100228753Smm#include "archive_string.h" 101228753Smm#include "archive_entry.h" 102228753Smm#include "archive_private.h" 103228753Smm 104228753Smm#ifndef O_BINARY 105228753Smm#define O_BINARY 0 106228753Smm#endif 107228753Smm 108228753Smmstruct fixup_entry { 109228753Smm struct fixup_entry *next; 110228753Smm mode_t mode; 111228753Smm int64_t atime; 112228753Smm int64_t birthtime; 113228753Smm int64_t mtime; 114228753Smm unsigned long atime_nanos; 115228753Smm unsigned long birthtime_nanos; 116228753Smm unsigned long mtime_nanos; 117228753Smm unsigned long fflags_set; 118228753Smm int fixup; /* bitmask of what needs fixing */ 119228753Smm char *name; 120228753Smm}; 121228753Smm 122228753Smm/* 123228753Smm * We use a bitmask to track which operations remain to be done for 124228753Smm * this file. In particular, this helps us avoid unnecessary 125228753Smm * operations when it's possible to take care of one step as a 126228753Smm * side-effect of another. For example, mkdir() can specify the mode 127228753Smm * for the newly-created object but symlink() cannot. This means we 128228753Smm * can skip chmod() if mkdir() succeeded, but we must explicitly 129228753Smm * chmod() if we're trying to create a directory that already exists 130228753Smm * (mkdir() failed) or if we're restoring a symlink. Similarly, we 131228753Smm * need to verify UID/GID before trying to restore SUID/SGID bits; 132228753Smm * that verification can occur explicitly through a stat() call or 133228753Smm * implicitly because of a successful chown() call. 134228753Smm */ 135228753Smm#define TODO_MODE_FORCE 0x40000000 136228753Smm#define TODO_MODE_BASE 0x20000000 137228753Smm#define TODO_SUID 0x10000000 138228753Smm#define TODO_SUID_CHECK 0x08000000 139228753Smm#define TODO_SGID 0x04000000 140228753Smm#define TODO_SGID_CHECK 0x02000000 141228753Smm#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID) 142228753Smm#define TODO_TIMES ARCHIVE_EXTRACT_TIME 143228753Smm#define TODO_OWNER ARCHIVE_EXTRACT_OWNER 144228753Smm#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS 145228753Smm#define TODO_ACLS ARCHIVE_EXTRACT_ACL 146228753Smm#define TODO_XATTR ARCHIVE_EXTRACT_XATTR 147228753Smm 148228753Smmstruct archive_write_disk { 149228753Smm struct archive archive; 150228753Smm 151228753Smm mode_t user_umask; 152228753Smm struct fixup_entry *fixup_list; 153228753Smm struct fixup_entry *current_fixup; 154228753Smm uid_t user_uid; 155228753Smm dev_t skip_file_dev; 156228753Smm ino_t skip_file_ino; 157228753Smm time_t start_time; 158228753Smm 159228753Smm gid_t (*lookup_gid)(void *private, const char *gname, gid_t gid); 160228753Smm void (*cleanup_gid)(void *private); 161228753Smm void *lookup_gid_data; 162228753Smm uid_t (*lookup_uid)(void *private, const char *gname, gid_t gid); 163228753Smm void (*cleanup_uid)(void *private); 164228753Smm void *lookup_uid_data; 165228753Smm 166228753Smm /* 167228753Smm * Full path of last file to satisfy symlink checks. 168228753Smm */ 169228753Smm struct archive_string path_safe; 170228753Smm 171228753Smm /* 172228753Smm * Cached stat data from disk for the current entry. 173228753Smm * If this is valid, pst points to st. Otherwise, 174228753Smm * pst is null. 175228753Smm */ 176228753Smm struct stat st; 177228753Smm struct stat *pst; 178228753Smm 179228753Smm /* Information about the object being restored right now. */ 180228753Smm struct archive_entry *entry; /* Entry being extracted. */ 181228753Smm char *name; /* Name of entry, possibly edited. */ 182228753Smm struct archive_string _name_data; /* backing store for 'name' */ 183228753Smm /* Tasks remaining for this object. */ 184228753Smm int todo; 185228753Smm /* Tasks deferred until end-of-archive. */ 186228753Smm int deferred; 187228753Smm /* Options requested by the client. */ 188228753Smm int flags; 189228753Smm /* Handle for the file we're restoring. */ 190228753Smm int fd; 191228753Smm /* Current offset for writing data to the file. */ 192228753Smm off_t offset; 193228753Smm /* Last offset actually written to disk. */ 194228753Smm off_t fd_offset; 195228753Smm /* Maximum size of file, -1 if unknown. */ 196228753Smm off_t filesize; 197228753Smm /* Dir we were in before this restore; only for deep paths. */ 198228753Smm int restore_pwd; 199228753Smm /* Mode we should use for this entry; affected by _PERM and umask. */ 200228753Smm mode_t mode; 201228753Smm /* UID/GID to use in restoring this entry. */ 202228753Smm uid_t uid; 203228753Smm gid_t gid; 204228753Smm}; 205228753Smm 206228753Smm/* 207228753Smm * Default mode for dirs created automatically (will be modified by umask). 208228753Smm * Note that POSIX specifies 0777 for implicity-created dirs, "modified 209228753Smm * by the process' file creation mask." 210228753Smm */ 211228753Smm#define DEFAULT_DIR_MODE 0777 212228753Smm/* 213228753Smm * Dir modes are restored in two steps: During the extraction, the permissions 214228753Smm * in the archive are modified to match the following limits. During 215228753Smm * the post-extract fixup pass, the permissions from the archive are 216228753Smm * applied. 217228753Smm */ 218228753Smm#define MINIMUM_DIR_MODE 0700 219228753Smm#define MAXIMUM_DIR_MODE 0775 220228753Smm 221228753Smmstatic int check_symlinks(struct archive_write_disk *); 222228753Smmstatic int create_filesystem_object(struct archive_write_disk *); 223228753Smmstatic struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname); 224228753Smm#ifdef HAVE_FCHDIR 225228753Smmstatic void edit_deep_directories(struct archive_write_disk *ad); 226228753Smm#endif 227228753Smmstatic int cleanup_pathname(struct archive_write_disk *); 228228753Smmstatic int create_dir(struct archive_write_disk *, char *); 229228753Smmstatic int create_parent_dir(struct archive_write_disk *, char *); 230228753Smmstatic int older(struct stat *, struct archive_entry *); 231228753Smmstatic int restore_entry(struct archive_write_disk *); 232228753Smm#ifdef HAVE_POSIX_ACL 233228753Smmstatic int set_acl(struct archive_write_disk *, int fd, struct archive_entry *, 234228753Smm acl_type_t, int archive_entry_acl_type, const char *tn); 235228753Smm#endif 236228753Smmstatic int set_acls(struct archive_write_disk *); 237228753Smmstatic int set_xattrs(struct archive_write_disk *); 238228753Smmstatic int set_fflags(struct archive_write_disk *); 239228753Smmstatic int set_fflags_platform(struct archive_write_disk *, int fd, 240228753Smm const char *name, mode_t mode, 241228753Smm unsigned long fflags_set, unsigned long fflags_clear); 242228753Smmstatic int set_ownership(struct archive_write_disk *); 243228753Smmstatic int set_mode(struct archive_write_disk *, int mode); 244228753Smmstatic int set_time(int, int, const char *, time_t, long, time_t, long); 245228753Smmstatic int set_times(struct archive_write_disk *); 246228753Smmstatic struct fixup_entry *sort_dir_list(struct fixup_entry *p); 247228753Smmstatic gid_t trivial_lookup_gid(void *, const char *, gid_t); 248228753Smmstatic uid_t trivial_lookup_uid(void *, const char *, uid_t); 249228753Smmstatic ssize_t write_data_block(struct archive_write_disk *, 250228753Smm const char *, size_t); 251228753Smm 252228753Smmstatic struct archive_vtable *archive_write_disk_vtable(void); 253228753Smm 254228753Smmstatic int _archive_write_close(struct archive *); 255229592Smmstatic int _archive_write_free(struct archive *); 256228753Smmstatic int _archive_write_header(struct archive *, struct archive_entry *); 257228753Smmstatic int _archive_write_finish_entry(struct archive *); 258228753Smmstatic ssize_t _archive_write_data(struct archive *, const void *, size_t); 259228753Smmstatic ssize_t _archive_write_data_block(struct archive *, const void *, size_t, off_t); 260228753Smm 261228753Smmstatic int 262228753Smm_archive_write_disk_lazy_stat(struct archive_write_disk *a) 263228753Smm{ 264228753Smm if (a->pst != NULL) { 265228753Smm /* Already have stat() data available. */ 266228753Smm return (ARCHIVE_OK); 267228753Smm } 268228753Smm#ifdef HAVE_FSTAT 269228753Smm if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) { 270228753Smm a->pst = &a->st; 271228753Smm return (ARCHIVE_OK); 272228753Smm } 273228753Smm#endif 274228753Smm /* 275228753Smm * XXX At this point, symlinks should not be hit, otherwise 276228753Smm * XXX a race occured. Do we want to check explicitly for that? 277228753Smm */ 278228753Smm if (lstat(a->name, &a->st) == 0) { 279228753Smm a->pst = &a->st; 280228753Smm return (ARCHIVE_OK); 281228753Smm } 282228753Smm archive_set_error(&a->archive, errno, "Couldn't stat file"); 283228753Smm return (ARCHIVE_WARN); 284228753Smm} 285228753Smm 286228753Smmstatic struct archive_vtable * 287228753Smmarchive_write_disk_vtable(void) 288228753Smm{ 289228753Smm static struct archive_vtable av; 290228753Smm static int inited = 0; 291228753Smm 292228753Smm if (!inited) { 293228753Smm av.archive_close = _archive_write_close; 294229592Smm av.archive_free = _archive_write_free; 295228753Smm av.archive_write_header = _archive_write_header; 296228753Smm av.archive_write_finish_entry = _archive_write_finish_entry; 297228753Smm av.archive_write_data = _archive_write_data; 298228753Smm av.archive_write_data_block = _archive_write_data_block; 299228753Smm } 300228753Smm return (&av); 301228753Smm} 302228753Smm 303228753Smm 304228753Smmint 305228753Smmarchive_write_disk_set_options(struct archive *_a, int flags) 306228753Smm{ 307228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 308228753Smm 309228753Smm a->flags = flags; 310228753Smm return (ARCHIVE_OK); 311228753Smm} 312228753Smm 313228753Smm 314228753Smm/* 315228753Smm * Extract this entry to disk. 316228753Smm * 317228753Smm * TODO: Validate hardlinks. According to the standards, we're 318228753Smm * supposed to check each extracted hardlink and squawk if it refers 319228753Smm * to a file that we didn't restore. I'm not entirely convinced this 320228753Smm * is a good idea, but more importantly: Is there any way to validate 321228753Smm * hardlinks without keeping a complete list of filenames from the 322228753Smm * entire archive?? Ugh. 323228753Smm * 324228753Smm */ 325228753Smmstatic int 326228753Smm_archive_write_header(struct archive *_a, struct archive_entry *entry) 327228753Smm{ 328228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 329228753Smm struct fixup_entry *fe; 330228753Smm int ret, r; 331228753Smm 332228753Smm __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 333228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 334228753Smm "archive_write_disk_header"); 335228753Smm archive_clear_error(&a->archive); 336228753Smm if (a->archive.state & ARCHIVE_STATE_DATA) { 337228753Smm r = _archive_write_finish_entry(&a->archive); 338228753Smm if (r == ARCHIVE_FATAL) 339228753Smm return (r); 340228753Smm } 341228753Smm 342228753Smm /* Set up for this particular entry. */ 343228753Smm a->pst = NULL; 344228753Smm a->current_fixup = NULL; 345228753Smm a->deferred = 0; 346228753Smm if (a->entry) { 347228753Smm archive_entry_free(a->entry); 348228753Smm a->entry = NULL; 349228753Smm } 350228753Smm a->entry = archive_entry_clone(entry); 351228753Smm a->fd = -1; 352228753Smm a->fd_offset = 0; 353228753Smm a->offset = 0; 354228753Smm a->uid = a->user_uid; 355228753Smm a->mode = archive_entry_mode(a->entry); 356228753Smm if (archive_entry_size_is_set(a->entry)) 357228753Smm a->filesize = archive_entry_size(a->entry); 358228753Smm else 359228753Smm a->filesize = -1; 360228753Smm archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry)); 361228753Smm a->name = a->_name_data.s; 362228753Smm archive_clear_error(&a->archive); 363228753Smm 364228753Smm /* 365228753Smm * Clean up the requested path. This is necessary for correct 366228753Smm * dir restores; the dir restore logic otherwise gets messed 367228753Smm * up by nonsense like "dir/.". 368228753Smm */ 369228753Smm ret = cleanup_pathname(a); 370228753Smm if (ret != ARCHIVE_OK) 371228753Smm return (ret); 372228753Smm 373228753Smm /* 374228753Smm * Set the umask to zero so we get predictable mode settings. 375228753Smm * This gets done on every call to _write_header in case the 376228753Smm * user edits their umask during the extraction for some 377228753Smm * reason. This will be reset before we return. Note that we 378228753Smm * don't need to do this in _finish_entry, as the chmod(), etc, 379228753Smm * system calls don't obey umask. 380228753Smm */ 381228753Smm a->user_umask = umask(0); 382228753Smm /* From here on, early exit requires "goto done" to clean up. */ 383228753Smm 384228753Smm /* Figure out what we need to do for this entry. */ 385228753Smm a->todo = TODO_MODE_BASE; 386228753Smm if (a->flags & ARCHIVE_EXTRACT_PERM) { 387228753Smm a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ 388228753Smm /* 389228753Smm * SGID requires an extra "check" step because we 390228753Smm * cannot easily predict the GID that the system will 391228753Smm * assign. (Different systems assign GIDs to files 392228753Smm * based on a variety of criteria, including process 393228753Smm * credentials and the gid of the enclosing 394228753Smm * directory.) We can only restore the SGID bit if 395228753Smm * the file has the right GID, and we only know the 396228753Smm * GID if we either set it (see set_ownership) or if 397228753Smm * we've actually called stat() on the file after it 398228753Smm * was restored. Since there are several places at 399228753Smm * which we might verify the GID, we need a TODO bit 400228753Smm * to keep track. 401228753Smm */ 402228753Smm if (a->mode & S_ISGID) 403228753Smm a->todo |= TODO_SGID | TODO_SGID_CHECK; 404228753Smm /* 405228753Smm * Verifying the SUID is simpler, but can still be 406228753Smm * done in multiple ways, hence the separate "check" bit. 407228753Smm */ 408228753Smm if (a->mode & S_ISUID) 409228753Smm a->todo |= TODO_SUID | TODO_SUID_CHECK; 410228753Smm } else { 411228753Smm /* 412228753Smm * User didn't request full permissions, so don't 413228753Smm * restore SUID, SGID bits and obey umask. 414228753Smm */ 415228753Smm a->mode &= ~S_ISUID; 416228753Smm a->mode &= ~S_ISGID; 417228753Smm a->mode &= ~S_ISVTX; 418228753Smm a->mode &= ~a->user_umask; 419228753Smm } 420228753Smm#if !defined(_WIN32) || defined(__CYGWIN__) 421228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) 422228753Smm a->todo |= TODO_OWNER; 423228753Smm#endif 424228753Smm if (a->flags & ARCHIVE_EXTRACT_TIME) 425228753Smm a->todo |= TODO_TIMES; 426228753Smm if (a->flags & ARCHIVE_EXTRACT_ACL) 427228753Smm a->todo |= TODO_ACLS; 428228753Smm if (a->flags & ARCHIVE_EXTRACT_XATTR) 429228753Smm a->todo |= TODO_XATTR; 430228753Smm if (a->flags & ARCHIVE_EXTRACT_FFLAGS) 431228753Smm a->todo |= TODO_FFLAGS; 432228753Smm if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { 433228753Smm ret = check_symlinks(a); 434228753Smm if (ret != ARCHIVE_OK) 435228753Smm goto done; 436228753Smm } 437228753Smm#ifdef HAVE_FCHDIR 438228753Smm /* If path exceeds PATH_MAX, shorten the path. */ 439228753Smm edit_deep_directories(a); 440228753Smm#endif 441228753Smm 442228753Smm ret = restore_entry(a); 443228753Smm 444228753Smm /* 445228753Smm * TODO: There are rumours that some extended attributes must 446228753Smm * be restored before file data is written. If this is true, 447228753Smm * then we either need to write all extended attributes both 448228753Smm * before and after restoring the data, or find some rule for 449228753Smm * determining which must go first and which last. Due to the 450228753Smm * many ways people are using xattrs, this may prove to be an 451228753Smm * intractable problem. 452228753Smm */ 453228753Smm 454228753Smm#ifdef HAVE_FCHDIR 455228753Smm /* If we changed directory above, restore it here. */ 456228753Smm if (a->restore_pwd >= 0) { 457228753Smm r = fchdir(a->restore_pwd); 458228753Smm if (r != 0) { 459228753Smm archive_set_error(&a->archive, errno, "chdir() failure"); 460228753Smm ret = ARCHIVE_FATAL; 461228753Smm } 462228753Smm close(a->restore_pwd); 463228753Smm a->restore_pwd = -1; 464228753Smm } 465228753Smm#endif 466228753Smm 467228753Smm /* 468228753Smm * Fixup uses the unedited pathname from archive_entry_pathname(), 469228753Smm * because it is relative to the base dir and the edited path 470228753Smm * might be relative to some intermediate dir as a result of the 471228753Smm * deep restore logic. 472228753Smm */ 473228753Smm if (a->deferred & TODO_MODE) { 474228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 475228753Smm fe->fixup |= TODO_MODE_BASE; 476228753Smm fe->mode = a->mode; 477228753Smm } 478228753Smm 479228753Smm if ((a->deferred & TODO_TIMES) 480228753Smm && (archive_entry_mtime_is_set(entry) 481228753Smm || archive_entry_atime_is_set(entry))) { 482228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 483228753Smm fe->fixup |= TODO_TIMES; 484228753Smm if (archive_entry_atime_is_set(entry)) { 485228753Smm fe->atime = archive_entry_atime(entry); 486228753Smm fe->atime_nanos = archive_entry_atime_nsec(entry); 487228753Smm } else { 488228753Smm /* If atime is unset, use start time. */ 489228753Smm fe->atime = a->start_time; 490228753Smm fe->atime_nanos = 0; 491228753Smm } 492228753Smm if (archive_entry_mtime_is_set(entry)) { 493228753Smm fe->mtime = archive_entry_mtime(entry); 494228753Smm fe->mtime_nanos = archive_entry_mtime_nsec(entry); 495228753Smm } else { 496228753Smm /* If mtime is unset, use start time. */ 497228753Smm fe->mtime = a->start_time; 498228753Smm fe->mtime_nanos = 0; 499228753Smm } 500228753Smm if (archive_entry_birthtime_is_set(entry)) { 501228753Smm fe->birthtime = archive_entry_birthtime(entry); 502228753Smm fe->birthtime_nanos = archive_entry_birthtime_nsec(entry); 503228753Smm } else { 504228753Smm /* If birthtime is unset, use mtime. */ 505228753Smm fe->birthtime = fe->mtime; 506228753Smm fe->birthtime_nanos = fe->mtime_nanos; 507228753Smm } 508228753Smm } 509228753Smm 510228753Smm if (a->deferred & TODO_FFLAGS) { 511228753Smm fe = current_fixup(a, archive_entry_pathname(entry)); 512228753Smm fe->fixup |= TODO_FFLAGS; 513228753Smm /* TODO: Complete this.. defer fflags from below. */ 514228753Smm } 515228753Smm 516228753Smm /* We've created the object and are ready to pour data into it. */ 517228753Smm if (ret >= ARCHIVE_WARN) 518228753Smm a->archive.state = ARCHIVE_STATE_DATA; 519228753Smm /* 520228753Smm * If it's not open, tell our client not to try writing. 521228753Smm * In particular, dirs, links, etc, don't get written to. 522228753Smm */ 523228753Smm if (a->fd < 0) { 524228753Smm archive_entry_set_size(entry, 0); 525228753Smm a->filesize = 0; 526228753Smm } 527228753Smmdone: 528228753Smm /* Restore the user's umask before returning. */ 529228753Smm umask(a->user_umask); 530228753Smm 531228753Smm return (ret); 532228753Smm} 533228753Smm 534228753Smmint 535228753Smmarchive_write_disk_set_skip_file(struct archive *_a, dev_t d, ino_t i) 536228753Smm{ 537228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 538228753Smm __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 539228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file"); 540228753Smm a->skip_file_dev = d; 541228753Smm a->skip_file_ino = i; 542228753Smm return (ARCHIVE_OK); 543228753Smm} 544228753Smm 545228753Smmstatic ssize_t 546228753Smmwrite_data_block(struct archive_write_disk *a, const char *buff, size_t size) 547228753Smm{ 548228753Smm uint64_t start_size = size; 549228753Smm ssize_t bytes_written = 0; 550228753Smm ssize_t block_size = 0, bytes_to_write; 551228753Smm 552228753Smm if (size == 0) 553228753Smm return (ARCHIVE_OK); 554228753Smm 555228753Smm if (a->filesize == 0 || a->fd < 0) { 556228753Smm archive_set_error(&a->archive, 0, 557228753Smm "Attempt to write to an empty file"); 558228753Smm return (ARCHIVE_WARN); 559228753Smm } 560228753Smm 561228753Smm if (a->flags & ARCHIVE_EXTRACT_SPARSE) { 562228753Smm#if HAVE_STRUCT_STAT_ST_BLKSIZE 563228753Smm int r; 564228753Smm if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK) 565228753Smm return (r); 566228753Smm block_size = a->pst->st_blksize; 567228753Smm#else 568228753Smm /* XXX TODO XXX Is there a more appropriate choice here ? */ 569228753Smm /* This needn't match the filesystem allocation size. */ 570228753Smm block_size = 16*1024; 571228753Smm#endif 572228753Smm } 573228753Smm 574228753Smm /* If this write would run beyond the file size, truncate it. */ 575228753Smm if (a->filesize >= 0 && (off_t)(a->offset + size) > a->filesize) 576228753Smm start_size = size = (size_t)(a->filesize - a->offset); 577228753Smm 578228753Smm /* Write the data. */ 579228753Smm while (size > 0) { 580228753Smm if (block_size == 0) { 581228753Smm bytes_to_write = size; 582228753Smm } else { 583228753Smm /* We're sparsifying the file. */ 584228753Smm const char *p, *end; 585228753Smm off_t block_end; 586228753Smm 587228753Smm /* Skip leading zero bytes. */ 588228753Smm for (p = buff, end = buff + size; p < end; ++p) { 589228753Smm if (*p != '\0') 590228753Smm break; 591228753Smm } 592228753Smm a->offset += p - buff; 593228753Smm size -= p - buff; 594228753Smm buff = p; 595228753Smm if (size == 0) 596228753Smm break; 597228753Smm 598228753Smm /* Calculate next block boundary after offset. */ 599228753Smm block_end 600228753Smm = (a->offset / block_size + 1) * block_size; 601228753Smm 602228753Smm /* If the adjusted write would cross block boundary, 603228753Smm * truncate it to the block boundary. */ 604228753Smm bytes_to_write = size; 605228753Smm if (a->offset + bytes_to_write > block_end) 606228753Smm bytes_to_write = block_end - a->offset; 607228753Smm } 608228753Smm /* Seek if necessary to the specified offset. */ 609228753Smm if (a->offset != a->fd_offset) { 610228753Smm if (lseek(a->fd, a->offset, SEEK_SET) < 0) { 611228753Smm archive_set_error(&a->archive, errno, 612228753Smm "Seek failed"); 613228753Smm return (ARCHIVE_FATAL); 614228753Smm } 615228753Smm a->fd_offset = a->offset; 616228753Smm a->archive.file_position = a->offset; 617228753Smm a->archive.raw_position = a->offset; 618228753Smm } 619228753Smm bytes_written = write(a->fd, buff, bytes_to_write); 620228753Smm if (bytes_written < 0) { 621228753Smm archive_set_error(&a->archive, errno, "Write failed"); 622228753Smm return (ARCHIVE_WARN); 623228753Smm } 624228753Smm buff += bytes_written; 625228753Smm size -= bytes_written; 626228753Smm a->offset += bytes_written; 627228753Smm a->archive.file_position += bytes_written; 628228753Smm a->archive.raw_position += bytes_written; 629228753Smm a->fd_offset = a->offset; 630228753Smm } 631228753Smm return (start_size - size); 632228753Smm} 633228753Smm 634228753Smmstatic ssize_t 635228753Smm_archive_write_data_block(struct archive *_a, 636228753Smm const void *buff, size_t size, off_t offset) 637228753Smm{ 638228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 639228753Smm ssize_t r; 640228753Smm 641228753Smm __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 642228753Smm ARCHIVE_STATE_DATA, "archive_write_disk_block"); 643228753Smm 644228753Smm a->offset = offset; 645228753Smm r = write_data_block(a, buff, size); 646228753Smm if (r < ARCHIVE_OK) 647228753Smm return (r); 648228753Smm if ((size_t)r < size) { 649228753Smm archive_set_error(&a->archive, 0, 650228753Smm "Write request too large"); 651228753Smm return (ARCHIVE_WARN); 652228753Smm } 653228753Smm return (ARCHIVE_OK); 654228753Smm} 655228753Smm 656228753Smmstatic ssize_t 657228753Smm_archive_write_data(struct archive *_a, const void *buff, size_t size) 658228753Smm{ 659228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 660228753Smm 661228753Smm __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 662228753Smm ARCHIVE_STATE_DATA, "archive_write_data"); 663228753Smm 664228753Smm return (write_data_block(a, buff, size)); 665228753Smm} 666228753Smm 667228753Smmstatic int 668228753Smm_archive_write_finish_entry(struct archive *_a) 669228753Smm{ 670228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 671228753Smm int ret = ARCHIVE_OK; 672228753Smm 673228753Smm __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 674228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 675228753Smm "archive_write_finish_entry"); 676228753Smm if (a->archive.state & ARCHIVE_STATE_HEADER) 677228753Smm return (ARCHIVE_OK); 678228753Smm archive_clear_error(&a->archive); 679228753Smm 680228753Smm /* Pad or truncate file to the right size. */ 681228753Smm if (a->fd < 0) { 682228753Smm /* There's no file. */ 683228753Smm } else if (a->filesize < 0) { 684228753Smm /* File size is unknown, so we can't set the size. */ 685228753Smm } else if (a->fd_offset == a->filesize) { 686228753Smm /* Last write ended at exactly the filesize; we're done. */ 687228753Smm /* Hopefully, this is the common case. */ 688228753Smm } else { 689228753Smm#if HAVE_FTRUNCATE 690228753Smm if (ftruncate(a->fd, a->filesize) == -1 && 691228753Smm a->filesize == 0) { 692228753Smm archive_set_error(&a->archive, errno, 693228753Smm "File size could not be restored"); 694228753Smm return (ARCHIVE_FAILED); 695228753Smm } 696228753Smm#endif 697228753Smm /* 698228753Smm * Not all platforms implement the XSI option to 699228753Smm * extend files via ftruncate. Stat() the file again 700228753Smm * to see what happened. 701228753Smm */ 702228753Smm a->pst = NULL; 703228753Smm if ((ret = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK) 704228753Smm return (ret); 705228753Smm /* We can use lseek()/write() to extend the file if 706228753Smm * ftruncate didn't work or isn't available. */ 707228753Smm if (a->st.st_size < a->filesize) { 708228753Smm const char nul = '\0'; 709228753Smm if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) { 710228753Smm archive_set_error(&a->archive, errno, 711228753Smm "Seek failed"); 712228753Smm return (ARCHIVE_FATAL); 713228753Smm } 714228753Smm if (write(a->fd, &nul, 1) < 0) { 715228753Smm archive_set_error(&a->archive, errno, 716228753Smm "Write to restore size failed"); 717228753Smm return (ARCHIVE_FATAL); 718228753Smm } 719228753Smm a->pst = NULL; 720228753Smm } 721228753Smm } 722228753Smm 723228753Smm /* Restore metadata. */ 724228753Smm 725228753Smm /* 726228753Smm * Look up the "real" UID only if we're going to need it. 727228753Smm * TODO: the TODO_SGID condition can be dropped here, can't it? 728228753Smm */ 729228753Smm if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { 730228753Smm a->uid = a->lookup_uid(a->lookup_uid_data, 731228753Smm archive_entry_uname(a->entry), 732228753Smm archive_entry_uid(a->entry)); 733228753Smm } 734228753Smm /* Look up the "real" GID only if we're going to need it. */ 735228753Smm /* TODO: the TODO_SUID condition can be dropped here, can't it? */ 736228753Smm if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { 737228753Smm a->gid = a->lookup_gid(a->lookup_gid_data, 738228753Smm archive_entry_gname(a->entry), 739228753Smm archive_entry_gid(a->entry)); 740228753Smm } 741228753Smm /* 742228753Smm * If restoring ownership, do it before trying to restore suid/sgid 743228753Smm * bits. If we set the owner, we know what it is and can skip 744228753Smm * a stat() call to examine the ownership of the file on disk. 745228753Smm */ 746228753Smm if (a->todo & TODO_OWNER) 747228753Smm ret = set_ownership(a); 748228753Smm if (a->todo & TODO_MODE) { 749228753Smm int r2 = set_mode(a, a->mode); 750228753Smm if (r2 < ret) ret = r2; 751228753Smm } 752228753Smm if (a->todo & TODO_ACLS) { 753228753Smm int r2 = set_acls(a); 754228753Smm if (r2 < ret) ret = r2; 755228753Smm } 756228753Smm 757228753Smm /* 758228753Smm * Security-related extended attributes (such as 759228753Smm * security.capability on Linux) have to be restored last, 760228753Smm * since they're implicitly removed by other file changes. 761228753Smm */ 762228753Smm if (a->todo & TODO_XATTR) { 763228753Smm int r2 = set_xattrs(a); 764228753Smm if (r2 < ret) ret = r2; 765228753Smm } 766228753Smm 767228753Smm /* 768228753Smm * Some flags prevent file modification; they must be restored after 769228753Smm * file contents are written. 770228753Smm */ 771228753Smm if (a->todo & TODO_FFLAGS) { 772228753Smm int r2 = set_fflags(a); 773228753Smm if (r2 < ret) ret = r2; 774228753Smm } 775228753Smm /* 776228753Smm * Time has to be restored after all other metadata; 777228753Smm * otherwise atime will get changed. 778228753Smm */ 779228753Smm if (a->todo & TODO_TIMES) { 780228753Smm int r2 = set_times(a); 781228753Smm if (r2 < ret) ret = r2; 782228753Smm } 783228753Smm 784228753Smm /* If there's an fd, we can close it now. */ 785228753Smm if (a->fd >= 0) { 786228753Smm close(a->fd); 787228753Smm a->fd = -1; 788228753Smm } 789228753Smm /* If there's an entry, we can release it now. */ 790228753Smm if (a->entry) { 791228753Smm archive_entry_free(a->entry); 792228753Smm a->entry = NULL; 793228753Smm } 794228753Smm a->archive.state = ARCHIVE_STATE_HEADER; 795228753Smm return (ret); 796228753Smm} 797228753Smm 798228753Smmint 799228753Smmarchive_write_disk_set_group_lookup(struct archive *_a, 800228753Smm void *private_data, 801228753Smm gid_t (*lookup_gid)(void *private, const char *gname, gid_t gid), 802228753Smm void (*cleanup_gid)(void *private)) 803228753Smm{ 804228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 805228753Smm __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 806228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); 807228753Smm 808228753Smm a->lookup_gid = lookup_gid; 809228753Smm a->cleanup_gid = cleanup_gid; 810228753Smm a->lookup_gid_data = private_data; 811228753Smm return (ARCHIVE_OK); 812228753Smm} 813228753Smm 814228753Smmint 815228753Smmarchive_write_disk_set_user_lookup(struct archive *_a, 816228753Smm void *private_data, 817228753Smm uid_t (*lookup_uid)(void *private, const char *uname, uid_t uid), 818228753Smm void (*cleanup_uid)(void *private)) 819228753Smm{ 820228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 821228753Smm __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 822228753Smm ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); 823228753Smm 824228753Smm a->lookup_uid = lookup_uid; 825228753Smm a->cleanup_uid = cleanup_uid; 826228753Smm a->lookup_uid_data = private_data; 827228753Smm return (ARCHIVE_OK); 828228753Smm} 829228753Smm 830228753Smm 831228753Smm/* 832228753Smm * Create a new archive_write_disk object and initialize it with global state. 833228753Smm */ 834228753Smmstruct archive * 835228753Smmarchive_write_disk_new(void) 836228753Smm{ 837228753Smm struct archive_write_disk *a; 838228753Smm 839228753Smm a = (struct archive_write_disk *)malloc(sizeof(*a)); 840228753Smm if (a == NULL) 841228753Smm return (NULL); 842228753Smm memset(a, 0, sizeof(*a)); 843228753Smm a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; 844228753Smm /* We're ready to write a header immediately. */ 845228753Smm a->archive.state = ARCHIVE_STATE_HEADER; 846228753Smm a->archive.vtable = archive_write_disk_vtable(); 847228753Smm a->lookup_uid = trivial_lookup_uid; 848228753Smm a->lookup_gid = trivial_lookup_gid; 849228753Smm a->start_time = time(NULL); 850228753Smm#ifdef HAVE_GETEUID 851228753Smm a->user_uid = geteuid(); 852228753Smm#endif /* HAVE_GETEUID */ 853228753Smm if (archive_string_ensure(&a->path_safe, 512) == NULL) { 854228753Smm free(a); 855228753Smm return (NULL); 856228753Smm } 857228753Smm return (&a->archive); 858228753Smm} 859228753Smm 860228753Smm 861228753Smm/* 862228753Smm * If pathname is longer than PATH_MAX, chdir to a suitable 863228753Smm * intermediate dir and edit the path down to a shorter suffix. Note 864228753Smm * that this routine never returns an error; if the chdir() attempt 865228753Smm * fails for any reason, we just go ahead with the long pathname. The 866228753Smm * object creation is likely to fail, but any error will get handled 867228753Smm * at that time. 868228753Smm */ 869228753Smm#ifdef HAVE_FCHDIR 870228753Smmstatic void 871228753Smmedit_deep_directories(struct archive_write_disk *a) 872228753Smm{ 873228753Smm int ret; 874228753Smm char *tail = a->name; 875228753Smm 876228753Smm a->restore_pwd = -1; 877228753Smm 878228753Smm /* If path is short, avoid the open() below. */ 879228753Smm if (strlen(tail) <= PATH_MAX) 880228753Smm return; 881228753Smm 882228753Smm /* Try to record our starting dir. */ 883228753Smm a->restore_pwd = open(".", O_RDONLY | O_BINARY); 884228753Smm if (a->restore_pwd < 0) 885228753Smm return; 886228753Smm 887228753Smm /* As long as the path is too long... */ 888228753Smm while (strlen(tail) > PATH_MAX) { 889228753Smm /* Locate a dir prefix shorter than PATH_MAX. */ 890228753Smm tail += PATH_MAX - 8; 891228753Smm while (tail > a->name && *tail != '/') 892228753Smm tail--; 893228753Smm /* Exit if we find a too-long path component. */ 894228753Smm if (tail <= a->name) 895228753Smm return; 896228753Smm /* Create the intermediate dir and chdir to it. */ 897228753Smm *tail = '\0'; /* Terminate dir portion */ 898228753Smm ret = create_dir(a, a->name); 899228753Smm if (ret == ARCHIVE_OK && chdir(a->name) != 0) 900228753Smm ret = ARCHIVE_FAILED; 901228753Smm *tail = '/'; /* Restore the / we removed. */ 902228753Smm if (ret != ARCHIVE_OK) 903228753Smm return; 904228753Smm tail++; 905228753Smm /* The chdir() succeeded; we've now shortened the path. */ 906228753Smm a->name = tail; 907228753Smm } 908228753Smm return; 909228753Smm} 910228753Smm#endif 911228753Smm 912228753Smm/* 913228753Smm * The main restore function. 914228753Smm */ 915228753Smmstatic int 916228753Smmrestore_entry(struct archive_write_disk *a) 917228753Smm{ 918228753Smm int ret = ARCHIVE_OK, en; 919228753Smm 920228753Smm if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { 921228753Smm /* 922228753Smm * TODO: Fix this. Apparently, there are platforms 923228753Smm * that still allow root to hose the entire filesystem 924228753Smm * by unlinking a dir. The S_ISDIR() test above 925228753Smm * prevents us from using unlink() here if the new 926228753Smm * object is a dir, but that doesn't mean the old 927228753Smm * object isn't a dir. 928228753Smm */ 929228753Smm if (unlink(a->name) == 0) { 930228753Smm /* We removed it, reset cached stat. */ 931228753Smm a->pst = NULL; 932228753Smm } else if (errno == ENOENT) { 933228753Smm /* File didn't exist, that's just as good. */ 934228753Smm } else if (rmdir(a->name) == 0) { 935228753Smm /* It was a dir, but now it's gone. */ 936228753Smm a->pst = NULL; 937228753Smm } else { 938228753Smm /* We tried, but couldn't get rid of it. */ 939228753Smm archive_set_error(&a->archive, errno, 940228753Smm "Could not unlink"); 941228753Smm return(ARCHIVE_FAILED); 942228753Smm } 943228753Smm } 944228753Smm 945228753Smm /* Try creating it first; if this fails, we'll try to recover. */ 946228753Smm en = create_filesystem_object(a); 947228753Smm 948228753Smm if ((en == ENOTDIR || en == ENOENT) 949228753Smm && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) { 950228753Smm /* If the parent dir doesn't exist, try creating it. */ 951228753Smm create_parent_dir(a, a->name); 952228753Smm /* Now try to create the object again. */ 953228753Smm en = create_filesystem_object(a); 954228753Smm } 955228753Smm 956228753Smm if ((en == EISDIR || en == EEXIST) 957228753Smm && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { 958228753Smm /* If we're not overwriting, we're done. */ 959228753Smm archive_set_error(&a->archive, en, "Already exists"); 960228753Smm return (ARCHIVE_FAILED); 961228753Smm } 962228753Smm 963228753Smm /* 964228753Smm * Some platforms return EISDIR if you call 965228753Smm * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some 966228753Smm * return EEXIST. POSIX is ambiguous, requiring EISDIR 967228753Smm * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT) 968228753Smm * on an existing item. 969228753Smm */ 970228753Smm if (en == EISDIR) { 971228753Smm /* A dir is in the way of a non-dir, rmdir it. */ 972228753Smm if (rmdir(a->name) != 0) { 973228753Smm archive_set_error(&a->archive, errno, 974228753Smm "Can't remove already-existing dir"); 975228753Smm return (ARCHIVE_FAILED); 976228753Smm } 977228753Smm a->pst = NULL; 978228753Smm /* Try again. */ 979228753Smm en = create_filesystem_object(a); 980228753Smm } else if (en == EEXIST) { 981228753Smm /* 982228753Smm * We know something is in the way, but we don't know what; 983228753Smm * we need to find out before we go any further. 984228753Smm */ 985228753Smm int r = 0; 986228753Smm /* 987228753Smm * The SECURE_SYMLINK logic has already removed a 988228753Smm * symlink to a dir if the client wants that. So 989228753Smm * follow the symlink if we're creating a dir. 990228753Smm */ 991228753Smm if (S_ISDIR(a->mode)) 992228753Smm r = stat(a->name, &a->st); 993228753Smm /* 994228753Smm * If it's not a dir (or it's a broken symlink), 995228753Smm * then don't follow it. 996228753Smm */ 997228753Smm if (r != 0 || !S_ISDIR(a->mode)) 998228753Smm r = lstat(a->name, &a->st); 999228753Smm if (r != 0) { 1000228753Smm archive_set_error(&a->archive, errno, 1001228753Smm "Can't stat existing object"); 1002228753Smm return (ARCHIVE_FAILED); 1003228753Smm } 1004228753Smm 1005228753Smm /* 1006228753Smm * NO_OVERWRITE_NEWER doesn't apply to directories. 1007228753Smm */ 1008228753Smm if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) 1009228753Smm && !S_ISDIR(a->st.st_mode)) { 1010228753Smm if (!older(&(a->st), a->entry)) { 1011228753Smm archive_set_error(&a->archive, 0, 1012228753Smm "File on disk is not older; skipping."); 1013228753Smm return (ARCHIVE_FAILED); 1014228753Smm } 1015228753Smm } 1016228753Smm 1017228753Smm /* If it's our archive, we're done. */ 1018228753Smm if (a->skip_file_dev > 0 && 1019228753Smm a->skip_file_ino > 0 && 1020228753Smm a->st.st_dev == a->skip_file_dev && 1021228753Smm a->st.st_ino == a->skip_file_ino) { 1022228753Smm archive_set_error(&a->archive, 0, "Refusing to overwrite archive"); 1023228753Smm return (ARCHIVE_FAILED); 1024228753Smm } 1025228753Smm 1026228753Smm if (!S_ISDIR(a->st.st_mode)) { 1027228753Smm /* A non-dir is in the way, unlink it. */ 1028228753Smm if (unlink(a->name) != 0) { 1029228753Smm archive_set_error(&a->archive, errno, 1030228753Smm "Can't unlink already-existing object"); 1031228753Smm return (ARCHIVE_FAILED); 1032228753Smm } 1033228753Smm a->pst = NULL; 1034228753Smm /* Try again. */ 1035228753Smm en = create_filesystem_object(a); 1036228753Smm } else if (!S_ISDIR(a->mode)) { 1037228753Smm /* A dir is in the way of a non-dir, rmdir it. */ 1038228753Smm if (rmdir(a->name) != 0) { 1039228753Smm archive_set_error(&a->archive, errno, 1040228753Smm "Can't remove already-existing dir"); 1041228753Smm return (ARCHIVE_FAILED); 1042228753Smm } 1043228753Smm /* Try again. */ 1044228753Smm en = create_filesystem_object(a); 1045228753Smm } else { 1046228753Smm /* 1047228753Smm * There's a dir in the way of a dir. Don't 1048228753Smm * waste time with rmdir()/mkdir(), just fix 1049228753Smm * up the permissions on the existing dir. 1050228753Smm * Note that we don't change perms on existing 1051228753Smm * dirs unless _EXTRACT_PERM is specified. 1052228753Smm */ 1053228753Smm if ((a->mode != a->st.st_mode) 1054228753Smm && (a->todo & TODO_MODE_FORCE)) 1055228753Smm a->deferred |= (a->todo & TODO_MODE); 1056228753Smm /* Ownership doesn't need deferred fixup. */ 1057228753Smm en = 0; /* Forget the EEXIST. */ 1058228753Smm } 1059228753Smm } 1060228753Smm 1061228753Smm if (en) { 1062228753Smm /* Everything failed; give up here. */ 1063228753Smm archive_set_error(&a->archive, en, "Can't create '%s'", 1064228753Smm a->name); 1065228753Smm return (ARCHIVE_FAILED); 1066228753Smm } 1067228753Smm 1068228753Smm a->pst = NULL; /* Cached stat data no longer valid. */ 1069228753Smm return (ret); 1070228753Smm} 1071228753Smm 1072228753Smm/* 1073228753Smm * Returns 0 if creation succeeds, or else returns errno value from 1074228753Smm * the failed system call. Note: This function should only ever perform 1075228753Smm * a single system call. 1076228753Smm */ 1077228753Smmstatic int 1078228753Smmcreate_filesystem_object(struct archive_write_disk *a) 1079228753Smm{ 1080228753Smm /* Create the entry. */ 1081228753Smm const char *linkname; 1082228753Smm mode_t final_mode, mode; 1083228753Smm int r; 1084228753Smm 1085228753Smm /* We identify hard/symlinks according to the link names. */ 1086228753Smm /* Since link(2) and symlink(2) don't handle modes, we're done here. */ 1087228753Smm linkname = archive_entry_hardlink(a->entry); 1088228753Smm if (linkname != NULL) { 1089228753Smm#if !HAVE_LINK 1090228753Smm return (EPERM); 1091228753Smm#else 1092228753Smm r = link(linkname, a->name) ? errno : 0; 1093228753Smm /* 1094228753Smm * New cpio and pax formats allow hardlink entries 1095228753Smm * to carry data, so we may have to open the file 1096228753Smm * for hardlink entries. 1097228753Smm * 1098228753Smm * If the hardlink was successfully created and 1099228753Smm * the archive doesn't have carry data for it, 1100228753Smm * consider it to be non-authoritive for meta data. 1101228753Smm * This is consistent with GNU tar and BSD pax. 1102228753Smm * If the hardlink does carry data, let the last 1103228753Smm * archive entry decide ownership. 1104228753Smm */ 1105228753Smm if (r == 0 && a->filesize <= 0) { 1106228753Smm a->todo = 0; 1107228753Smm a->deferred = 0; 1108228753Smm } if (r == 0 && a->filesize > 0) { 1109228753Smm a->fd = open(a->name, O_WRONLY | O_TRUNC | O_BINARY); 1110228753Smm if (a->fd < 0) 1111228753Smm r = errno; 1112228753Smm } 1113228753Smm return (r); 1114228753Smm#endif 1115228753Smm } 1116228753Smm linkname = archive_entry_symlink(a->entry); 1117228753Smm if (linkname != NULL) { 1118228753Smm#if HAVE_SYMLINK 1119228753Smm return symlink(linkname, a->name) ? errno : 0; 1120228753Smm#else 1121228753Smm return (EPERM); 1122228753Smm#endif 1123228753Smm } 1124228753Smm 1125228753Smm /* 1126228753Smm * The remaining system calls all set permissions, so let's 1127228753Smm * try to take advantage of that to avoid an extra chmod() 1128228753Smm * call. (Recall that umask is set to zero right now!) 1129228753Smm */ 1130228753Smm 1131228753Smm /* Mode we want for the final restored object (w/o file type bits). */ 1132228753Smm final_mode = a->mode & 07777; 1133228753Smm /* 1134228753Smm * The mode that will actually be restored in this step. Note 1135228753Smm * that SUID, SGID, etc, require additional work to ensure 1136228753Smm * security, so we never restore them at this point. 1137228753Smm */ 1138228753Smm mode = final_mode & 0777; 1139228753Smm 1140228753Smm switch (a->mode & AE_IFMT) { 1141228753Smm default: 1142228753Smm /* POSIX requires that we fall through here. */ 1143228753Smm /* FALLTHROUGH */ 1144228753Smm case AE_IFREG: 1145228753Smm a->fd = open(a->name, 1146228753Smm O_WRONLY | O_CREAT | O_EXCL | O_BINARY, mode); 1147228753Smm r = (a->fd < 0); 1148228753Smm break; 1149228753Smm case AE_IFCHR: 1150228753Smm#ifdef HAVE_MKNOD 1151228753Smm /* Note: we use AE_IFCHR for the case label, and 1152228753Smm * S_IFCHR for the mknod() call. This is correct. */ 1153228753Smm r = mknod(a->name, mode | S_IFCHR, 1154228753Smm archive_entry_rdev(a->entry)); 1155228753Smm break; 1156228753Smm#else 1157228753Smm /* TODO: Find a better way to warn about our inability 1158228753Smm * to restore a char device node. */ 1159228753Smm return (EINVAL); 1160228753Smm#endif /* HAVE_MKNOD */ 1161228753Smm case AE_IFBLK: 1162228753Smm#ifdef HAVE_MKNOD 1163228753Smm r = mknod(a->name, mode | S_IFBLK, 1164228753Smm archive_entry_rdev(a->entry)); 1165228753Smm break; 1166228753Smm#else 1167228753Smm /* TODO: Find a better way to warn about our inability 1168228753Smm * to restore a block device node. */ 1169228753Smm return (EINVAL); 1170228753Smm#endif /* HAVE_MKNOD */ 1171228753Smm case AE_IFDIR: 1172228753Smm mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; 1173228753Smm r = mkdir(a->name, mode); 1174228753Smm if (r == 0) { 1175228753Smm /* Defer setting dir times. */ 1176228753Smm a->deferred |= (a->todo & TODO_TIMES); 1177228753Smm a->todo &= ~TODO_TIMES; 1178228753Smm /* Never use an immediate chmod(). */ 1179228753Smm /* We can't avoid the chmod() entirely if EXTRACT_PERM 1180228753Smm * because of SysV SGID inheritance. */ 1181228753Smm if ((mode != final_mode) 1182228753Smm || (a->flags & ARCHIVE_EXTRACT_PERM)) 1183228753Smm a->deferred |= (a->todo & TODO_MODE); 1184228753Smm a->todo &= ~TODO_MODE; 1185228753Smm } 1186228753Smm break; 1187228753Smm case AE_IFIFO: 1188228753Smm#ifdef HAVE_MKFIFO 1189228753Smm r = mkfifo(a->name, mode); 1190228753Smm break; 1191228753Smm#else 1192228753Smm /* TODO: Find a better way to warn about our inability 1193228753Smm * to restore a fifo. */ 1194228753Smm return (EINVAL); 1195228753Smm#endif /* HAVE_MKFIFO */ 1196228753Smm } 1197228753Smm 1198228753Smm /* All the system calls above set errno on failure. */ 1199228753Smm if (r) 1200228753Smm return (errno); 1201228753Smm 1202228753Smm /* If we managed to set the final mode, we've avoided a chmod(). */ 1203228753Smm if (mode == final_mode) 1204228753Smm a->todo &= ~TODO_MODE; 1205228753Smm return (0); 1206228753Smm} 1207228753Smm 1208228753Smm/* 1209228753Smm * Cleanup function for archive_extract. Mostly, this involves processing 1210228753Smm * the fixup list, which is used to address a number of problems: 1211228753Smm * * Dir permissions might prevent us from restoring a file in that 1212228753Smm * dir, so we restore the dir with minimum 0700 permissions first, 1213228753Smm * then correct the mode at the end. 1214228753Smm * * Similarly, the act of restoring a file touches the directory 1215228753Smm * and changes the timestamp on the dir, so we have to touch-up dir 1216228753Smm * timestamps at the end as well. 1217228753Smm * * Some file flags can interfere with the restore by, for example, 1218228753Smm * preventing the creation of hardlinks to those files. 1219228753Smm * 1220228753Smm * Note that tar/cpio do not require that archives be in a particular 1221228753Smm * order; there is no way to know when the last file has been restored 1222228753Smm * within a directory, so there's no way to optimize the memory usage 1223228753Smm * here by fixing up the directory any earlier than the 1224228753Smm * end-of-archive. 1225228753Smm * 1226228753Smm * XXX TODO: Directory ACLs should be restored here, for the same 1227228753Smm * reason we set directory perms here. XXX 1228228753Smm */ 1229228753Smmstatic int 1230228753Smm_archive_write_close(struct archive *_a) 1231228753Smm{ 1232228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1233228753Smm struct fixup_entry *next, *p; 1234228753Smm int ret; 1235228753Smm 1236228753Smm __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, 1237228753Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1238228753Smm "archive_write_disk_close"); 1239228753Smm ret = _archive_write_finish_entry(&a->archive); 1240228753Smm 1241228753Smm /* Sort dir list so directories are fixed up in depth-first order. */ 1242228753Smm p = sort_dir_list(a->fixup_list); 1243228753Smm 1244228753Smm while (p != NULL) { 1245228753Smm a->pst = NULL; /* Mark stat cache as out-of-date. */ 1246228753Smm if (p->fixup & TODO_TIMES) { 1247228753Smm#ifdef HAVE_UTIMES 1248228753Smm /* {f,l,}utimes() are preferred, when available. */ 1249228753Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1250228753Smm struct __timeval times[2]; 1251228753Smm#else 1252228753Smm struct timeval times[2]; 1253228753Smm#endif 1254228753Smm times[0].tv_sec = p->atime; 1255228753Smm times[0].tv_usec = p->atime_nanos / 1000; 1256228753Smm#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME 1257228753Smm /* if it's valid and not mtime, push the birthtime first */ 1258228753Smm if (((times[1].tv_sec = p->birthtime) < p->mtime) && 1259228753Smm (p->birthtime > 0)) 1260228753Smm { 1261228753Smm times[1].tv_usec = p->birthtime_nanos / 1000; 1262228753Smm utimes(p->name, times); 1263228753Smm } 1264228753Smm#endif 1265228753Smm times[1].tv_sec = p->mtime; 1266228753Smm times[1].tv_usec = p->mtime_nanos / 1000; 1267228753Smm#ifdef HAVE_LUTIMES 1268228753Smm lutimes(p->name, times); 1269228753Smm#else 1270228753Smm utimes(p->name, times); 1271228753Smm#endif 1272228753Smm#else 1273228753Smm /* utime() is more portable, but less precise. */ 1274228753Smm struct utimbuf times; 1275228753Smm times.modtime = p->mtime; 1276228753Smm times.actime = p->atime; 1277228753Smm 1278228753Smm utime(p->name, ×); 1279228753Smm#endif 1280228753Smm } 1281228753Smm if (p->fixup & TODO_MODE_BASE) 1282228753Smm chmod(p->name, p->mode); 1283228753Smm 1284228753Smm if (p->fixup & TODO_FFLAGS) 1285228753Smm set_fflags_platform(a, -1, p->name, 1286228753Smm p->mode, p->fflags_set, 0); 1287228753Smm 1288228753Smm next = p->next; 1289228753Smm free(p->name); 1290228753Smm free(p); 1291228753Smm p = next; 1292228753Smm } 1293228753Smm a->fixup_list = NULL; 1294228753Smm return (ret); 1295228753Smm} 1296228753Smm 1297228753Smmstatic int 1298229592Smm_archive_write_free(struct archive *_a) 1299228753Smm{ 1300228753Smm struct archive_write_disk *a = (struct archive_write_disk *)_a; 1301228753Smm int ret; 1302228753Smm ret = _archive_write_close(&a->archive); 1303228753Smm if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) 1304228753Smm (a->cleanup_gid)(a->lookup_gid_data); 1305228753Smm if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) 1306228753Smm (a->cleanup_uid)(a->lookup_uid_data); 1307228753Smm if (a->entry) 1308228753Smm archive_entry_free(a->entry); 1309228753Smm archive_string_free(&a->_name_data); 1310228753Smm archive_string_free(&a->archive.error_string); 1311228753Smm archive_string_free(&a->path_safe); 1312228753Smm free(a); 1313228753Smm return (ret); 1314228753Smm} 1315228753Smm 1316228753Smm/* 1317228753Smm * Simple O(n log n) merge sort to order the fixup list. In 1318228753Smm * particular, we want to restore dir timestamps depth-first. 1319228753Smm */ 1320228753Smmstatic struct fixup_entry * 1321228753Smmsort_dir_list(struct fixup_entry *p) 1322228753Smm{ 1323228753Smm struct fixup_entry *a, *b, *t; 1324228753Smm 1325228753Smm if (p == NULL) 1326228753Smm return (NULL); 1327228753Smm /* A one-item list is already sorted. */ 1328228753Smm if (p->next == NULL) 1329228753Smm return (p); 1330228753Smm 1331228753Smm /* Step 1: split the list. */ 1332228753Smm t = p; 1333228753Smm a = p->next->next; 1334228753Smm while (a != NULL) { 1335228753Smm /* Step a twice, t once. */ 1336228753Smm a = a->next; 1337228753Smm if (a != NULL) 1338228753Smm a = a->next; 1339228753Smm t = t->next; 1340228753Smm } 1341228753Smm /* Now, t is at the mid-point, so break the list here. */ 1342228753Smm b = t->next; 1343228753Smm t->next = NULL; 1344228753Smm a = p; 1345228753Smm 1346228753Smm /* Step 2: Recursively sort the two sub-lists. */ 1347228753Smm a = sort_dir_list(a); 1348228753Smm b = sort_dir_list(b); 1349228753Smm 1350228753Smm /* Step 3: Merge the returned lists. */ 1351228753Smm /* Pick the first element for the merged list. */ 1352228753Smm if (strcmp(a->name, b->name) > 0) { 1353228753Smm t = p = a; 1354228753Smm a = a->next; 1355228753Smm } else { 1356228753Smm t = p = b; 1357228753Smm b = b->next; 1358228753Smm } 1359228753Smm 1360228753Smm /* Always put the later element on the list first. */ 1361228753Smm while (a != NULL && b != NULL) { 1362228753Smm if (strcmp(a->name, b->name) > 0) { 1363228753Smm t->next = a; 1364228753Smm a = a->next; 1365228753Smm } else { 1366228753Smm t->next = b; 1367228753Smm b = b->next; 1368228753Smm } 1369228753Smm t = t->next; 1370228753Smm } 1371228753Smm 1372228753Smm /* Only one list is non-empty, so just splice it on. */ 1373228753Smm if (a != NULL) 1374228753Smm t->next = a; 1375228753Smm if (b != NULL) 1376228753Smm t->next = b; 1377228753Smm 1378228753Smm return (p); 1379228753Smm} 1380228753Smm 1381228753Smm/* 1382228753Smm * Returns a new, initialized fixup entry. 1383228753Smm * 1384228753Smm * TODO: Reduce the memory requirements for this list by using a tree 1385228753Smm * structure rather than a simple list of names. 1386228753Smm */ 1387228753Smmstatic struct fixup_entry * 1388228753Smmnew_fixup(struct archive_write_disk *a, const char *pathname) 1389228753Smm{ 1390228753Smm struct fixup_entry *fe; 1391228753Smm 1392228753Smm fe = (struct fixup_entry *)malloc(sizeof(struct fixup_entry)); 1393228753Smm if (fe == NULL) 1394228753Smm return (NULL); 1395228753Smm fe->next = a->fixup_list; 1396228753Smm a->fixup_list = fe; 1397228753Smm fe->fixup = 0; 1398228753Smm fe->name = strdup(pathname); 1399228753Smm return (fe); 1400228753Smm} 1401228753Smm 1402228753Smm/* 1403228753Smm * Returns a fixup structure for the current entry. 1404228753Smm */ 1405228753Smmstatic struct fixup_entry * 1406228753Smmcurrent_fixup(struct archive_write_disk *a, const char *pathname) 1407228753Smm{ 1408228753Smm if (a->current_fixup == NULL) 1409228753Smm a->current_fixup = new_fixup(a, pathname); 1410228753Smm return (a->current_fixup); 1411228753Smm} 1412228753Smm 1413228753Smm/* TODO: Make this work. */ 1414228753Smm/* 1415228753Smm * TODO: The deep-directory support bypasses this; disable deep directory 1416228753Smm * support if we're doing symlink checks. 1417228753Smm */ 1418228753Smm/* 1419228753Smm * TODO: Someday, integrate this with the deep dir support; they both 1420228753Smm * scan the path and both can be optimized by comparing against other 1421228753Smm * recent paths. 1422228753Smm */ 1423228753Smm/* TODO: Extend this to support symlinks on Windows Vista and later. */ 1424228753Smmstatic int 1425228753Smmcheck_symlinks(struct archive_write_disk *a) 1426228753Smm{ 1427228753Smm#if !defined(HAVE_LSTAT) 1428228753Smm /* Platform doesn't have lstat, so we can't look for symlinks. */ 1429228753Smm (void)a; /* UNUSED */ 1430228753Smm return (ARCHIVE_OK); 1431228753Smm#else 1432228753Smm char *pn, *p; 1433228753Smm char c; 1434228753Smm int r; 1435228753Smm struct stat st; 1436228753Smm 1437228753Smm /* 1438228753Smm * Guard against symlink tricks. Reject any archive entry whose 1439228753Smm * destination would be altered by a symlink. 1440228753Smm */ 1441228753Smm /* Whatever we checked last time doesn't need to be re-checked. */ 1442228753Smm pn = a->name; 1443228753Smm p = a->path_safe.s; 1444228753Smm while ((*pn != '\0') && (*p == *pn)) 1445228753Smm ++p, ++pn; 1446228753Smm c = pn[0]; 1447228753Smm /* Keep going until we've checked the entire name. */ 1448228753Smm while (pn[0] != '\0' && (pn[0] != '/' || pn[1] != '\0')) { 1449228753Smm /* Skip the next path element. */ 1450228753Smm while (*pn != '\0' && *pn != '/') 1451228753Smm ++pn; 1452228753Smm c = pn[0]; 1453228753Smm pn[0] = '\0'; 1454228753Smm /* Check that we haven't hit a symlink. */ 1455228753Smm r = lstat(a->name, &st); 1456228753Smm if (r != 0) { 1457228753Smm /* We've hit a dir that doesn't exist; stop now. */ 1458228753Smm if (errno == ENOENT) 1459228753Smm break; 1460228753Smm } else if (S_ISLNK(st.st_mode)) { 1461228753Smm if (c == '\0') { 1462228753Smm /* 1463228753Smm * Last element is symlink; remove it 1464228753Smm * so we can overwrite it with the 1465228753Smm * item being extracted. 1466228753Smm */ 1467228753Smm if (unlink(a->name)) { 1468228753Smm archive_set_error(&a->archive, errno, 1469228753Smm "Could not remove symlink %s", 1470228753Smm a->name); 1471228753Smm pn[0] = c; 1472228753Smm return (ARCHIVE_FAILED); 1473228753Smm } 1474228753Smm a->pst = NULL; 1475228753Smm /* 1476228753Smm * Even if we did remove it, a warning 1477228753Smm * is in order. The warning is silly, 1478228753Smm * though, if we're just replacing one 1479228753Smm * symlink with another symlink. 1480228753Smm */ 1481228753Smm if (!S_ISLNK(a->mode)) { 1482228753Smm archive_set_error(&a->archive, 0, 1483228753Smm "Removing symlink %s", 1484228753Smm a->name); 1485228753Smm } 1486228753Smm /* Symlink gone. No more problem! */ 1487228753Smm pn[0] = c; 1488228753Smm return (0); 1489228753Smm } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) { 1490228753Smm /* User asked us to remove problems. */ 1491228753Smm if (unlink(a->name) != 0) { 1492228753Smm archive_set_error(&a->archive, 0, 1493228753Smm "Cannot remove intervening symlink %s", 1494228753Smm a->name); 1495228753Smm pn[0] = c; 1496228753Smm return (ARCHIVE_FAILED); 1497228753Smm } 1498228753Smm a->pst = NULL; 1499228753Smm } else { 1500228753Smm archive_set_error(&a->archive, 0, 1501228753Smm "Cannot extract through symlink %s", 1502228753Smm a->name); 1503228753Smm pn[0] = c; 1504228753Smm return (ARCHIVE_FAILED); 1505228753Smm } 1506228753Smm } 1507228753Smm } 1508228753Smm pn[0] = c; 1509228753Smm /* We've checked and/or cleaned the whole path, so remember it. */ 1510228753Smm archive_strcpy(&a->path_safe, a->name); 1511228753Smm return (ARCHIVE_OK); 1512228753Smm#endif 1513228753Smm} 1514228753Smm 1515228753Smm#if defined(_WIN32) || defined(__CYGWIN__) 1516228753Smmstatic int 1517228753Smmguidword(const char *p, int n) 1518228753Smm{ 1519228753Smm int i; 1520228753Smm 1521228753Smm for (i = 0; i < n; i++) { 1522228753Smm if ((*p >= '0' && *p <= '9') || 1523228753Smm (*p >= 'a' && *p <= 'f') || 1524228753Smm (*p >= 'A' && *p <= 'F')) 1525228753Smm p++; 1526228753Smm else 1527228753Smm return (-1); 1528228753Smm } 1529228753Smm return (0); 1530228753Smm} 1531228753Smm 1532228753Smm/* 1533228753Smm * 1. Convert a path separator from '\' to '/' . 1534228753Smm * We shouldn't check multi-byte character directly because some 1535228753Smm * character-set have been using the '\' character for a part of 1536228753Smm * its multibyte character code. 1537228753Smm * 2. Replace unusable characters in Windows with underscore('_'). 1538228753Smm * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx 1539228753Smm */ 1540228753Smmstatic int 1541228753Smmcleanup_pathname_win(struct archive_write_disk *a) 1542228753Smm{ 1543228753Smm wchar_t wc; 1544228753Smm char *p; 1545228753Smm size_t alen, l; 1546228753Smm 1547228753Smm p = a->name; 1548228753Smm /* Skip leading "\\.\" or "\\?\" or "\\?\UNC\" or 1549228753Smm * "\\?\Volume{GUID}\" 1550228753Smm * (absolute path prefixes used by Windows API) */ 1551228753Smm if ((p[0] == '\\' || p[0] == '/') && (p[1] == '\\' || p[1] == '/' ) && 1552228753Smm (p[2] == '.' || p[2] == '?') && (p[3] == '\\' || p[3] == '/')) 1553228753Smm { 1554228753Smm /* A path begin with "\\?\UNC\" */ 1555228753Smm if (p[2] == '?' && 1556228753Smm (p[4] == 'U' || p[4] == 'u') && 1557228753Smm (p[5] == 'N' || p[5] == 'n') && 1558228753Smm (p[6] == 'C' || p[6] == 'c') && 1559228753Smm (p[7] == '\\' || p[7] == '/')) 1560228753Smm p += 8; 1561228753Smm /* A path begin with "\\?\Volume{GUID}\" */ 1562228753Smm else if (p[2] == '?' && 1563228753Smm (p[4] == 'V' || p[4] == 'v') && 1564228753Smm (p[5] == 'O' || p[5] == 'o') && 1565228753Smm (p[6] == 'L' || p[6] == 'l') && 1566228753Smm (p[7] == 'U' || p[7] == 'u') && 1567228753Smm (p[8] == 'M' || p[8] == 'm') && 1568228753Smm (p[9] == 'E' || p[9] == 'e') && 1569228753Smm p[10] == '{') { 1570228753Smm if (guidword(p+11, 8) == 0 && p[19] == '-' && 1571228753Smm guidword(p+20, 4) == 0 && p[24] == '-' && 1572228753Smm guidword(p+25, 4) == 0 && p[29] == '-' && 1573228753Smm guidword(p+30, 4) == 0 && p[34] == '-' && 1574228753Smm guidword(p+35, 12) == 0 && p[47] == '}' && 1575228753Smm (p[48] == '\\' || p[48] == '/')) 1576228753Smm p += 49; 1577228753Smm else 1578228753Smm p += 4; 1579228753Smm /* A path begin with "\\.\PhysicalDriveX" */ 1580228753Smm } else if (p[2] == '.' && 1581228753Smm (p[4] == 'P' || p[4] == 'p') && 1582228753Smm (p[5] == 'H' || p[5] == 'h') && 1583228753Smm (p[6] == 'Y' || p[6] == 'y') && 1584228753Smm (p[7] == 'S' || p[7] == 's') && 1585228753Smm (p[8] == 'I' || p[8] == 'i') && 1586228753Smm (p[9] == 'C' || p[9] == 'c') && 1587228753Smm (p[9] == 'A' || p[9] == 'a') && 1588228753Smm (p[9] == 'L' || p[9] == 'l') && 1589228753Smm (p[9] == 'D' || p[9] == 'd') && 1590228753Smm (p[9] == 'R' || p[9] == 'r') && 1591228753Smm (p[9] == 'I' || p[9] == 'i') && 1592228753Smm (p[9] == 'V' || p[9] == 'v') && 1593228753Smm (p[9] == 'E' || p[9] == 'e') && 1594228753Smm (p[10] >= '0' && p[10] <= '9') && 1595228753Smm p[11] == '\0') { 1596228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1597228753Smm "Path is a physical drive name"); 1598228753Smm return (ARCHIVE_FAILED); 1599228753Smm } else 1600228753Smm p += 4; 1601228753Smm } 1602228753Smm 1603228753Smm /* Skip leading drive letter from archives created 1604228753Smm * on Windows. */ 1605228753Smm if (((p[0] >= 'a' && p[0] <= 'z') || 1606228753Smm (p[0] >= 'A' && p[0] <= 'Z')) && 1607228753Smm p[1] == ':') { 1608228753Smm if (p[2] == '\0') { 1609228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1610228753Smm "Path is a drive name"); 1611228753Smm return (ARCHIVE_FAILED); 1612228753Smm } 1613228753Smm if (p[2] == '\\' || p[2] == '/') 1614228753Smm p += 3; 1615228753Smm } 1616228753Smm 1617228753Smm for (; *p != '\0'; p++) { 1618228753Smm /* Rewrite the path name if its character is a unusable. */ 1619228753Smm if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || 1620228753Smm *p == '<' || *p == '>' || *p == '|') 1621228753Smm *p = '_'; 1622228753Smm } 1623228753Smm alen = p - a->name; 1624228753Smm if (alen == 0 || strchr(a->name, '\\') == NULL) 1625228753Smm return (ARCHIVE_OK); 1626228753Smm /* 1627228753Smm * Convert path separator. 1628228753Smm */ 1629228753Smm p = a->name; 1630228753Smm while (*p != '\0' && alen) { 1631228753Smm l = mbtowc(&wc, p, alen); 1632228753Smm if (l == -1) { 1633228753Smm while (*p != '\0') { 1634228753Smm if (*p == '\\') 1635228753Smm *p = '/'; 1636228753Smm ++p; 1637228753Smm } 1638228753Smm break; 1639228753Smm } 1640228753Smm if (l == 1 && wc == L'\\') 1641228753Smm *p = '/'; 1642228753Smm p += l; 1643228753Smm alen -= l; 1644228753Smm } 1645228753Smm return (ARCHIVE_OK); 1646228753Smm} 1647228753Smm#endif 1648228753Smm 1649228753Smm/* 1650228753Smm * Canonicalize the pathname. In particular, this strips duplicate 1651228753Smm * '/' characters, '.' elements, and trailing '/'. It also raises an 1652228753Smm * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is 1653228753Smm * set) any '..' in the path. 1654228753Smm */ 1655228753Smmstatic int 1656228753Smmcleanup_pathname(struct archive_write_disk *a) 1657228753Smm{ 1658228753Smm char *dest, *src; 1659228753Smm char separator = '\0'; 1660228753Smm 1661228753Smm dest = src = a->name; 1662228753Smm if (*src == '\0') { 1663228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1664228753Smm "Invalid empty pathname"); 1665228753Smm return (ARCHIVE_FAILED); 1666228753Smm } 1667228753Smm 1668228753Smm#if defined(_WIN32) || defined(__CYGWIN__) 1669228753Smm if (cleanup_pathname_win(a) != ARCHIVE_OK) 1670228753Smm return (ARCHIVE_FAILED); 1671228753Smm#endif 1672228753Smm /* Skip leading '/'. */ 1673228753Smm if (*src == '/') 1674228753Smm separator = *src++; 1675228753Smm 1676228753Smm /* Scan the pathname one element at a time. */ 1677228753Smm for (;;) { 1678228753Smm /* src points to first char after '/' */ 1679228753Smm if (src[0] == '\0') { 1680228753Smm break; 1681228753Smm } else if (src[0] == '/') { 1682228753Smm /* Found '//', ignore second one. */ 1683228753Smm src++; 1684228753Smm continue; 1685228753Smm } else if (src[0] == '.') { 1686228753Smm if (src[1] == '\0') { 1687228753Smm /* Ignore trailing '.' */ 1688228753Smm break; 1689228753Smm } else if (src[1] == '/') { 1690228753Smm /* Skip './'. */ 1691228753Smm src += 2; 1692228753Smm continue; 1693228753Smm } else if (src[1] == '.') { 1694228753Smm if (src[2] == '/' || src[2] == '\0') { 1695228753Smm /* Conditionally warn about '..' */ 1696228753Smm if (a->flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) { 1697228753Smm archive_set_error(&a->archive, 1698228753Smm ARCHIVE_ERRNO_MISC, 1699228753Smm "Path contains '..'"); 1700228753Smm return (ARCHIVE_FAILED); 1701228753Smm } 1702228753Smm } 1703228753Smm /* 1704228753Smm * Note: Under no circumstances do we 1705228753Smm * remove '..' elements. In 1706228753Smm * particular, restoring 1707228753Smm * '/foo/../bar/' should create the 1708228753Smm * 'foo' dir as a side-effect. 1709228753Smm */ 1710228753Smm } 1711228753Smm } 1712228753Smm 1713228753Smm /* Copy current element, including leading '/'. */ 1714228753Smm if (separator) 1715228753Smm *dest++ = '/'; 1716228753Smm while (*src != '\0' && *src != '/') { 1717228753Smm *dest++ = *src++; 1718228753Smm } 1719228753Smm 1720228753Smm if (*src == '\0') 1721228753Smm break; 1722228753Smm 1723228753Smm /* Skip '/' separator. */ 1724228753Smm separator = *src++; 1725228753Smm } 1726228753Smm /* 1727228753Smm * We've just copied zero or more path elements, not including the 1728228753Smm * final '/'. 1729228753Smm */ 1730228753Smm if (dest == a->name) { 1731228753Smm /* 1732228753Smm * Nothing got copied. The path must have been something 1733228753Smm * like '.' or '/' or './' or '/././././/./'. 1734228753Smm */ 1735228753Smm if (separator) 1736228753Smm *dest++ = '/'; 1737228753Smm else 1738228753Smm *dest++ = '.'; 1739228753Smm } 1740228753Smm /* Terminate the result. */ 1741228753Smm *dest = '\0'; 1742228753Smm return (ARCHIVE_OK); 1743228753Smm} 1744228753Smm 1745228753Smm/* 1746228753Smm * Create the parent directory of the specified path, assuming path 1747228753Smm * is already in mutable storage. 1748228753Smm */ 1749228753Smmstatic int 1750228753Smmcreate_parent_dir(struct archive_write_disk *a, char *path) 1751228753Smm{ 1752228753Smm char *slash; 1753228753Smm int r; 1754228753Smm 1755228753Smm /* Remove tail element to obtain parent name. */ 1756228753Smm slash = strrchr(path, '/'); 1757228753Smm if (slash == NULL) 1758228753Smm return (ARCHIVE_OK); 1759228753Smm *slash = '\0'; 1760228753Smm r = create_dir(a, path); 1761228753Smm *slash = '/'; 1762228753Smm return (r); 1763228753Smm} 1764228753Smm 1765228753Smm/* 1766228753Smm * Create the specified dir, recursing to create parents as necessary. 1767228753Smm * 1768228753Smm * Returns ARCHIVE_OK if the path exists when we're done here. 1769228753Smm * Otherwise, returns ARCHIVE_FAILED. 1770228753Smm * Assumes path is in mutable storage; path is unchanged on exit. 1771228753Smm */ 1772228753Smmstatic int 1773228753Smmcreate_dir(struct archive_write_disk *a, char *path) 1774228753Smm{ 1775228753Smm struct stat st; 1776228753Smm struct fixup_entry *le; 1777228753Smm char *slash, *base; 1778228753Smm mode_t mode_final, mode; 1779228753Smm int r; 1780228753Smm 1781228753Smm /* Check for special names and just skip them. */ 1782228753Smm slash = strrchr(path, '/'); 1783228753Smm if (slash == NULL) 1784228753Smm base = path; 1785228753Smm else 1786228753Smm base = slash + 1; 1787228753Smm 1788228753Smm if (base[0] == '\0' || 1789228753Smm (base[0] == '.' && base[1] == '\0') || 1790228753Smm (base[0] == '.' && base[1] == '.' && base[2] == '\0')) { 1791228753Smm /* Don't bother trying to create null path, '.', or '..'. */ 1792228753Smm if (slash != NULL) { 1793228753Smm *slash = '\0'; 1794228753Smm r = create_dir(a, path); 1795228753Smm *slash = '/'; 1796228753Smm return (r); 1797228753Smm } 1798228753Smm return (ARCHIVE_OK); 1799228753Smm } 1800228753Smm 1801228753Smm /* 1802228753Smm * Yes, this should be stat() and not lstat(). Using lstat() 1803228753Smm * here loses the ability to extract through symlinks. Also note 1804228753Smm * that this should not use the a->st cache. 1805228753Smm */ 1806228753Smm if (stat(path, &st) == 0) { 1807228753Smm if (S_ISDIR(st.st_mode)) 1808228753Smm return (ARCHIVE_OK); 1809228753Smm if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { 1810228753Smm archive_set_error(&a->archive, EEXIST, 1811228753Smm "Can't create directory '%s'", path); 1812228753Smm return (ARCHIVE_FAILED); 1813228753Smm } 1814228753Smm if (unlink(path) != 0) { 1815228753Smm archive_set_error(&a->archive, errno, 1816228753Smm "Can't create directory '%s': " 1817228753Smm "Conflicting file cannot be removed", path); 1818228753Smm return (ARCHIVE_FAILED); 1819228753Smm } 1820228753Smm } else if (errno != ENOENT && errno != ENOTDIR) { 1821228753Smm /* Stat failed? */ 1822228753Smm archive_set_error(&a->archive, errno, "Can't test directory '%s'", path); 1823228753Smm return (ARCHIVE_FAILED); 1824228753Smm } else if (slash != NULL) { 1825228753Smm *slash = '\0'; 1826228753Smm r = create_dir(a, path); 1827228753Smm *slash = '/'; 1828228753Smm if (r != ARCHIVE_OK) 1829228753Smm return (r); 1830228753Smm } 1831228753Smm 1832228753Smm /* 1833228753Smm * Mode we want for the final restored directory. Per POSIX, 1834228753Smm * implicitly-created dirs must be created obeying the umask. 1835228753Smm * There's no mention whether this is different for privileged 1836228753Smm * restores (which the rest of this code handles by pretending 1837228753Smm * umask=0). I've chosen here to always obey the user's umask for 1838228753Smm * implicit dirs, even if _EXTRACT_PERM was specified. 1839228753Smm */ 1840228753Smm mode_final = DEFAULT_DIR_MODE & ~a->user_umask; 1841228753Smm /* Mode we want on disk during the restore process. */ 1842228753Smm mode = mode_final; 1843228753Smm mode |= MINIMUM_DIR_MODE; 1844228753Smm mode &= MAXIMUM_DIR_MODE; 1845228753Smm if (mkdir(path, mode) == 0) { 1846228753Smm if (mode != mode_final) { 1847228753Smm le = new_fixup(a, path); 1848228753Smm le->fixup |=TODO_MODE_BASE; 1849228753Smm le->mode = mode_final; 1850228753Smm } 1851228753Smm return (ARCHIVE_OK); 1852228753Smm } 1853228753Smm 1854228753Smm /* 1855228753Smm * Without the following check, a/b/../b/c/d fails at the 1856228753Smm * second visit to 'b', so 'd' can't be created. Note that we 1857228753Smm * don't add it to the fixup list here, as it's already been 1858228753Smm * added. 1859228753Smm */ 1860228753Smm if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) 1861228753Smm return (ARCHIVE_OK); 1862228753Smm 1863228753Smm archive_set_error(&a->archive, errno, "Failed to create dir '%s'", 1864228753Smm path); 1865228753Smm return (ARCHIVE_FAILED); 1866228753Smm} 1867228753Smm 1868228753Smm/* 1869228753Smm * Note: Although we can skip setting the user id if the desired user 1870228753Smm * id matches the current user, we cannot skip setting the group, as 1871228753Smm * many systems set the gid based on the containing directory. So 1872228753Smm * we have to perform a chown syscall if we want to set the SGID 1873228753Smm * bit. (The alternative is to stat() and then possibly chown(); it's 1874228753Smm * more efficient to skip the stat() and just always chown().) Note 1875228753Smm * that a successful chown() here clears the TODO_SGID_CHECK bit, which 1876228753Smm * allows set_mode to skip the stat() check for the GID. 1877228753Smm */ 1878228753Smmstatic int 1879228753Smmset_ownership(struct archive_write_disk *a) 1880228753Smm{ 1881228753Smm#ifndef __CYGWIN__ 1882228753Smm/* unfortunately, on win32 there is no 'root' user with uid 0, 1883228753Smm so we just have to try the chown and see if it works */ 1884228753Smm 1885228753Smm /* If we know we can't change it, don't bother trying. */ 1886228753Smm if (a->user_uid != 0 && a->user_uid != a->uid) { 1887228753Smm archive_set_error(&a->archive, errno, 1888228753Smm "Can't set UID=%d", a->uid); 1889228753Smm return (ARCHIVE_WARN); 1890228753Smm } 1891228753Smm#endif 1892228753Smm 1893228753Smm#ifdef HAVE_FCHOWN 1894228753Smm /* If we have an fd, we can avoid a race. */ 1895228753Smm if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) { 1896228753Smm /* We've set owner and know uid/gid are correct. */ 1897228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 1898228753Smm return (ARCHIVE_OK); 1899228753Smm } 1900228753Smm#endif 1901228753Smm 1902228753Smm /* We prefer lchown() but will use chown() if that's all we have. */ 1903228753Smm /* Of course, if we have neither, this will always fail. */ 1904228753Smm#ifdef HAVE_LCHOWN 1905228753Smm if (lchown(a->name, a->uid, a->gid) == 0) { 1906228753Smm /* We've set owner and know uid/gid are correct. */ 1907228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 1908228753Smm return (ARCHIVE_OK); 1909228753Smm } 1910228753Smm#elif HAVE_CHOWN 1911228753Smm if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) { 1912228753Smm /* We've set owner and know uid/gid are correct. */ 1913228753Smm a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); 1914228753Smm return (ARCHIVE_OK); 1915228753Smm } 1916228753Smm#endif 1917228753Smm 1918228753Smm archive_set_error(&a->archive, errno, 1919228753Smm "Can't set user=%d/group=%d for %s", a->uid, a->gid, 1920228753Smm a->name); 1921228753Smm return (ARCHIVE_WARN); 1922228753Smm} 1923228753Smm 1924228753Smm 1925228753Smm#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS) 1926228753Smm/* 1927228753Smm * utimensat() and futimens() are defined in POSIX.1-2008. They provide ns 1928228753Smm * resolution and setting times on fd and on symlinks, too. 1929228753Smm */ 1930228753Smmstatic int 1931228753Smmset_time(int fd, int mode, const char *name, 1932228753Smm time_t atime, long atime_nsec, 1933228753Smm time_t mtime, long mtime_nsec) 1934228753Smm{ 1935228753Smm struct timespec ts[2]; 1936228753Smm ts[0].tv_sec = atime; 1937228753Smm ts[0].tv_nsec = atime_nsec; 1938228753Smm ts[1].tv_sec = mtime; 1939228753Smm ts[1].tv_nsec = mtime_nsec; 1940228753Smm if (fd >= 0) 1941228753Smm return futimens(fd, ts); 1942228753Smm return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW); 1943228753Smm} 1944228753Smm#elif HAVE_UTIMES 1945228753Smm/* 1946228753Smm * The utimes()-family functions provide ��s-resolution and 1947228753Smm * a way to set time on an fd or a symlink. We prefer them 1948228753Smm * when they're available and utimensat/futimens aren't there. 1949228753Smm */ 1950228753Smmstatic int 1951228753Smmset_time(int fd, int mode, const char *name, 1952228753Smm time_t atime, long atime_nsec, 1953228753Smm time_t mtime, long mtime_nsec) 1954228753Smm{ 1955228753Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1956228753Smm struct __timeval times[2]; 1957228753Smm#else 1958228753Smm struct timeval times[2]; 1959228753Smm#endif 1960228753Smm 1961228753Smm times[0].tv_sec = atime; 1962228753Smm times[0].tv_usec = atime_nsec / 1000; 1963228753Smm times[1].tv_sec = mtime; 1964228753Smm times[1].tv_usec = mtime_nsec / 1000; 1965228753Smm 1966228753Smm#ifdef HAVE_FUTIMES 1967228753Smm if (fd >= 0) 1968228753Smm return (futimes(fd, times)); 1969228753Smm#else 1970228753Smm (void)fd; /* UNUSED */ 1971228753Smm#endif 1972228753Smm#ifdef HAVE_LUTIMES 1973228753Smm (void)mode; /* UNUSED */ 1974228753Smm return (lutimes(name, times)); 1975228753Smm#else 1976228753Smm if (S_ISLNK(mode)) 1977228753Smm return (0); 1978228753Smm return (utimes(name, times)); 1979228753Smm#endif 1980228753Smm} 1981228753Smm#elif defined(HAVE_UTIME) 1982228753Smm/* 1983228753Smm * utime() is an older, more standard interface that we'll use 1984228753Smm * if utimes() isn't available. 1985228753Smm */ 1986228753Smmstatic int 1987228753Smmset_time(int fd, int mode, const char *name, 1988228753Smm time_t atime, long atime_nsec, 1989228753Smm time_t mtime, long mtime_nsec) 1990228753Smm{ 1991228753Smm struct utimbuf times; 1992228753Smm (void)fd; /* UNUSED */ 1993228753Smm (void)name; /* UNUSED */ 1994228753Smm (void)atime_nsec; /* UNUSED */ 1995228753Smm (void)mtime_nsec; /* UNUSED */ 1996228753Smm times.actime = atime; 1997228753Smm times.modtime = mtime; 1998228753Smm if (S_ISLNK(mode)) 1999228753Smm return (ARCHIVE_OK); 2000228753Smm return (utime(name, ×)); 2001228753Smm} 2002228753Smm#else 2003228753Smmstatic int 2004228753Smmset_time(int fd, int mode, const char *name, 2005228753Smm time_t atime, long atime_nsec, 2006228753Smm time_t mtime, long mtime_nsec) 2007228753Smm{ 2008228753Smm return (ARCHIVE_WARN); 2009228753Smm} 2010228753Smm#endif 2011228753Smm 2012228753Smmstatic int 2013228753Smmset_times(struct archive_write_disk *a) 2014228753Smm{ 2015228753Smm time_t atime = a->start_time, mtime = a->start_time; 2016228753Smm long atime_nsec = 0, mtime_nsec = 0; 2017228753Smm 2018228753Smm /* If no time was provided, we're done. */ 2019228753Smm if (!archive_entry_atime_is_set(a->entry) 2020228753Smm#if HAVE_STRUCT_STAT_ST_BIRTHTIME 2021228753Smm && !archive_entry_birthtime_is_set(a->entry) 2022228753Smm#endif 2023228753Smm && !archive_entry_mtime_is_set(a->entry)) 2024228753Smm return (ARCHIVE_OK); 2025228753Smm 2026228753Smm /* If no atime was specified, use start time instead. */ 2027228753Smm /* In theory, it would be marginally more correct to use 2028228753Smm * time(NULL) here, but that would cost us an extra syscall 2029228753Smm * for little gain. */ 2030228753Smm if (archive_entry_atime_is_set(a->entry)) { 2031228753Smm atime = archive_entry_atime(a->entry); 2032228753Smm atime_nsec = archive_entry_atime_nsec(a->entry); 2033228753Smm } 2034228753Smm 2035228753Smm /* 2036228753Smm * If you have struct stat.st_birthtime, we assume BSD birthtime 2037228753Smm * semantics, in which {f,l,}utimes() updates birthtime to earliest 2038228753Smm * mtime. So we set the time twice, first using the birthtime, 2039228753Smm * then using the mtime. 2040228753Smm */ 2041228753Smm#if HAVE_STRUCT_STAT_ST_BIRTHTIME 2042228753Smm /* If birthtime is set, flush that through to disk first. */ 2043228753Smm if (archive_entry_birthtime_is_set(a->entry)) 2044228753Smm if (set_time(a->fd, a->mode, a->name, atime, atime_nsec, 2045228753Smm archive_entry_birthtime(a->entry), 2046228753Smm archive_entry_birthtime_nsec(a->entry))) { 2047228753Smm archive_set_error(&a->archive, errno, 2048228753Smm "Can't update time for %s", 2049228753Smm a->name); 2050228753Smm return (ARCHIVE_WARN); 2051228753Smm } 2052228753Smm#endif 2053228753Smm 2054228753Smm if (archive_entry_mtime_is_set(a->entry)) { 2055228753Smm mtime = archive_entry_mtime(a->entry); 2056228753Smm mtime_nsec = archive_entry_mtime_nsec(a->entry); 2057228753Smm } 2058228753Smm if (set_time(a->fd, a->mode, a->name, 2059228753Smm atime, atime_nsec, mtime, mtime_nsec)) { 2060228753Smm archive_set_error(&a->archive, errno, 2061228753Smm "Can't update time for %s", 2062228753Smm a->name); 2063228753Smm return (ARCHIVE_WARN); 2064228753Smm } 2065228753Smm 2066228753Smm /* 2067228753Smm * Note: POSIX does not provide a portable way to restore ctime. 2068228753Smm * (Apart from resetting the system clock, which is distasteful.) 2069228753Smm * So, any restoration of ctime will necessarily be OS-specific. 2070228753Smm */ 2071228753Smm 2072228753Smm return (ARCHIVE_OK); 2073228753Smm} 2074228753Smm 2075228753Smmstatic int 2076228753Smmset_mode(struct archive_write_disk *a, int mode) 2077228753Smm{ 2078228753Smm int r = ARCHIVE_OK; 2079228753Smm mode &= 07777; /* Strip off file type bits. */ 2080228753Smm 2081228753Smm if (a->todo & TODO_SGID_CHECK) { 2082228753Smm /* 2083228753Smm * If we don't know the GID is right, we must stat() 2084228753Smm * to verify it. We can't just check the GID of this 2085228753Smm * process, since systems sometimes set GID from 2086228753Smm * the enclosing dir or based on ACLs. 2087228753Smm */ 2088228753Smm if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK) 2089228753Smm return (r); 2090228753Smm if (a->pst->st_gid != a->gid) { 2091228753Smm mode &= ~ S_ISGID; 2092228753Smm#if !defined(_WIN32) || defined(__CYGWIN__) 2093228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 2094228753Smm /* 2095228753Smm * This is only an error if you 2096228753Smm * requested owner restore. If you 2097228753Smm * didn't, we'll try to restore 2098228753Smm * sgid/suid, but won't consider it a 2099228753Smm * problem if we can't. 2100228753Smm */ 2101228753Smm archive_set_error(&a->archive, -1, 2102228753Smm "Can't restore SGID bit"); 2103228753Smm r = ARCHIVE_WARN; 2104228753Smm } 2105228753Smm#endif 2106228753Smm } 2107228753Smm /* While we're here, double-check the UID. */ 2108228753Smm if (a->pst->st_uid != a->uid 2109228753Smm && (a->todo & TODO_SUID)) { 2110228753Smm mode &= ~ S_ISUID; 2111228753Smm#if !defined(_WIN32) || defined(__CYGWIN__) 2112228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 2113228753Smm archive_set_error(&a->archive, -1, 2114228753Smm "Can't restore SUID bit"); 2115228753Smm r = ARCHIVE_WARN; 2116228753Smm } 2117228753Smm#endif 2118228753Smm } 2119228753Smm a->todo &= ~TODO_SGID_CHECK; 2120228753Smm a->todo &= ~TODO_SUID_CHECK; 2121228753Smm } else if (a->todo & TODO_SUID_CHECK) { 2122228753Smm /* 2123228753Smm * If we don't know the UID is right, we can just check 2124228753Smm * the user, since all systems set the file UID from 2125228753Smm * the process UID. 2126228753Smm */ 2127228753Smm if (a->user_uid != a->uid) { 2128228753Smm mode &= ~ S_ISUID; 2129228753Smm#if !defined(_WIN32) || defined(__CYGWIN__) 2130228753Smm if (a->flags & ARCHIVE_EXTRACT_OWNER) { 2131228753Smm archive_set_error(&a->archive, -1, 2132228753Smm "Can't make file SUID"); 2133228753Smm r = ARCHIVE_WARN; 2134228753Smm } 2135228753Smm#endif 2136228753Smm } 2137228753Smm a->todo &= ~TODO_SUID_CHECK; 2138228753Smm } 2139228753Smm 2140228753Smm if (S_ISLNK(a->mode)) { 2141228753Smm#ifdef HAVE_LCHMOD 2142228753Smm /* 2143228753Smm * If this is a symlink, use lchmod(). If the 2144228753Smm * platform doesn't support lchmod(), just skip it. A 2145228753Smm * platform that doesn't provide a way to set 2146228753Smm * permissions on symlinks probably ignores 2147228753Smm * permissions on symlinks, so a failure here has no 2148228753Smm * impact. 2149228753Smm */ 2150228753Smm if (lchmod(a->name, mode) != 0) { 2151228753Smm archive_set_error(&a->archive, errno, 2152228753Smm "Can't set permissions to 0%o", (int)mode); 2153228753Smm r = ARCHIVE_WARN; 2154228753Smm } 2155228753Smm#endif 2156228753Smm } else if (!S_ISDIR(a->mode)) { 2157228753Smm /* 2158228753Smm * If it's not a symlink and not a dir, then use 2159228753Smm * fchmod() or chmod(), depending on whether we have 2160228753Smm * an fd. Dirs get their perms set during the 2161228753Smm * post-extract fixup, which is handled elsewhere. 2162228753Smm */ 2163228753Smm#ifdef HAVE_FCHMOD 2164228753Smm if (a->fd >= 0) { 2165228753Smm if (fchmod(a->fd, mode) != 0) { 2166228753Smm archive_set_error(&a->archive, errno, 2167228753Smm "Can't set permissions to 0%o", (int)mode); 2168228753Smm r = ARCHIVE_WARN; 2169228753Smm } 2170228753Smm } else 2171228753Smm#endif 2172228753Smm /* If this platform lacks fchmod(), then 2173228753Smm * we'll just use chmod(). */ 2174228753Smm if (chmod(a->name, mode) != 0) { 2175228753Smm archive_set_error(&a->archive, errno, 2176228753Smm "Can't set permissions to 0%o", (int)mode); 2177228753Smm r = ARCHIVE_WARN; 2178228753Smm } 2179228753Smm } 2180228753Smm return (r); 2181228753Smm} 2182228753Smm 2183228753Smmstatic int 2184228753Smmset_fflags(struct archive_write_disk *a) 2185228753Smm{ 2186228753Smm struct fixup_entry *le; 2187228753Smm unsigned long set, clear; 2188228753Smm int r; 2189228753Smm int critical_flags; 2190228753Smm mode_t mode = archive_entry_mode(a->entry); 2191228753Smm 2192228753Smm /* 2193228753Smm * Make 'critical_flags' hold all file flags that can't be 2194228753Smm * immediately restored. For example, on BSD systems, 2195228753Smm * SF_IMMUTABLE prevents hardlinks from being created, so 2196228753Smm * should not be set until after any hardlinks are created. To 2197228753Smm * preserve some semblance of portability, this uses #ifdef 2198228753Smm * extensively. Ugly, but it works. 2199228753Smm * 2200228753Smm * Yes, Virginia, this does create a security race. It's mitigated 2201228753Smm * somewhat by the practice of creating dirs 0700 until the extract 2202228753Smm * is done, but it would be nice if we could do more than that. 2203228753Smm * People restoring critical file systems should be wary of 2204228753Smm * other programs that might try to muck with files as they're 2205228753Smm * being restored. 2206228753Smm */ 2207228753Smm /* Hopefully, the compiler will optimize this mess into a constant. */ 2208228753Smm critical_flags = 0; 2209228753Smm#ifdef SF_IMMUTABLE 2210228753Smm critical_flags |= SF_IMMUTABLE; 2211228753Smm#endif 2212228753Smm#ifdef UF_IMMUTABLE 2213228753Smm critical_flags |= UF_IMMUTABLE; 2214228753Smm#endif 2215228753Smm#ifdef SF_APPEND 2216228753Smm critical_flags |= SF_APPEND; 2217228753Smm#endif 2218228753Smm#ifdef UF_APPEND 2219228753Smm critical_flags |= UF_APPEND; 2220228753Smm#endif 2221228753Smm#ifdef EXT2_APPEND_FL 2222228753Smm critical_flags |= EXT2_APPEND_FL; 2223228753Smm#endif 2224228753Smm#ifdef EXT2_IMMUTABLE_FL 2225228753Smm critical_flags |= EXT2_IMMUTABLE_FL; 2226228753Smm#endif 2227228753Smm 2228228753Smm if (a->todo & TODO_FFLAGS) { 2229228753Smm archive_entry_fflags(a->entry, &set, &clear); 2230228753Smm 2231228753Smm /* 2232228753Smm * The first test encourages the compiler to eliminate 2233228753Smm * all of this if it's not necessary. 2234228753Smm */ 2235228753Smm if ((critical_flags != 0) && (set & critical_flags)) { 2236228753Smm le = current_fixup(a, a->name); 2237228753Smm le->fixup |= TODO_FFLAGS; 2238228753Smm le->fflags_set = set; 2239228753Smm /* Store the mode if it's not already there. */ 2240228753Smm if ((le->fixup & TODO_MODE) == 0) 2241228753Smm le->mode = mode; 2242228753Smm } else { 2243228753Smm r = set_fflags_platform(a, a->fd, 2244228753Smm a->name, mode, set, clear); 2245228753Smm if (r != ARCHIVE_OK) 2246228753Smm return (r); 2247228753Smm } 2248228753Smm } 2249228753Smm return (ARCHIVE_OK); 2250228753Smm} 2251228753Smm 2252228753Smm 2253228753Smm#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS) 2254228753Smm/* 2255228753Smm * BSD reads flags using stat() and sets them with one of {f,l,}chflags() 2256228753Smm */ 2257228753Smmstatic int 2258228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 2259228753Smm mode_t mode, unsigned long set, unsigned long clear) 2260228753Smm{ 2261228753Smm int r; 2262228753Smm 2263228753Smm (void)mode; /* UNUSED */ 2264228753Smm if (set == 0 && clear == 0) 2265228753Smm return (ARCHIVE_OK); 2266228753Smm 2267228753Smm /* 2268228753Smm * XXX Is the stat here really necessary? Or can I just use 2269228753Smm * the 'set' flags directly? In particular, I'm not sure 2270228753Smm * about the correct approach if we're overwriting an existing 2271228753Smm * file that already has flags on it. XXX 2272228753Smm */ 2273228753Smm if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK) 2274228753Smm return (r); 2275228753Smm 2276228753Smm a->st.st_flags &= ~clear; 2277228753Smm a->st.st_flags |= set; 2278228753Smm#ifdef HAVE_FCHFLAGS 2279228753Smm /* If platform has fchflags() and we were given an fd, use it. */ 2280228753Smm if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0) 2281228753Smm return (ARCHIVE_OK); 2282228753Smm#endif 2283228753Smm /* 2284228753Smm * If we can't use the fd to set the flags, we'll use the 2285228753Smm * pathname to set flags. We prefer lchflags() but will use 2286228753Smm * chflags() if we must. 2287228753Smm */ 2288228753Smm#ifdef HAVE_LCHFLAGS 2289228753Smm if (lchflags(name, a->st.st_flags) == 0) 2290228753Smm return (ARCHIVE_OK); 2291228753Smm#elif defined(HAVE_CHFLAGS) 2292228753Smm if (S_ISLNK(a->st.st_mode)) { 2293228753Smm archive_set_error(&a->archive, errno, 2294228753Smm "Can't set file flags on symlink."); 2295228753Smm return (ARCHIVE_WARN); 2296228753Smm } 2297228753Smm if (chflags(name, a->st.st_flags) == 0) 2298228753Smm return (ARCHIVE_OK); 2299228753Smm#endif 2300228753Smm archive_set_error(&a->archive, errno, 2301228753Smm "Failed to set file flags"); 2302228753Smm return (ARCHIVE_WARN); 2303228753Smm} 2304228753Smm 2305228753Smm#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) 2306228753Smm/* 2307228753Smm * Linux uses ioctl() to read and write file flags. 2308228753Smm */ 2309228753Smmstatic int 2310228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 2311228753Smm mode_t mode, unsigned long set, unsigned long clear) 2312228753Smm{ 2313228753Smm int ret; 2314228753Smm int myfd = fd; 2315228753Smm unsigned long newflags, oldflags; 2316228753Smm unsigned long sf_mask = 0; 2317228753Smm 2318228753Smm if (set == 0 && clear == 0) 2319228753Smm return (ARCHIVE_OK); 2320228753Smm /* Only regular files and dirs can have flags. */ 2321228753Smm if (!S_ISREG(mode) && !S_ISDIR(mode)) 2322228753Smm return (ARCHIVE_OK); 2323228753Smm 2324228753Smm /* If we weren't given an fd, open it ourselves. */ 2325228753Smm if (myfd < 0) 2326228753Smm myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY); 2327228753Smm if (myfd < 0) 2328228753Smm return (ARCHIVE_OK); 2329228753Smm 2330228753Smm /* 2331228753Smm * Linux has no define for the flags that are only settable by 2332228753Smm * the root user. This code may seem a little complex, but 2333228753Smm * there seem to be some Linux systems that lack these 2334228753Smm * defines. (?) The code below degrades reasonably gracefully 2335228753Smm * if sf_mask is incomplete. 2336228753Smm */ 2337228753Smm#ifdef EXT2_IMMUTABLE_FL 2338228753Smm sf_mask |= EXT2_IMMUTABLE_FL; 2339228753Smm#endif 2340228753Smm#ifdef EXT2_APPEND_FL 2341228753Smm sf_mask |= EXT2_APPEND_FL; 2342228753Smm#endif 2343228753Smm /* 2344228753Smm * XXX As above, this would be way simpler if we didn't have 2345228753Smm * to read the current flags from disk. XXX 2346228753Smm */ 2347228753Smm ret = ARCHIVE_OK; 2348228753Smm /* Try setting the flags as given. */ 2349228753Smm if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) { 2350228753Smm newflags = (oldflags & ~clear) | set; 2351228753Smm if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0) 2352228753Smm goto cleanup; 2353228753Smm if (errno != EPERM) 2354228753Smm goto fail; 2355228753Smm } 2356228753Smm /* If we couldn't set all the flags, try again with a subset. */ 2357228753Smm if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) { 2358228753Smm newflags &= ~sf_mask; 2359228753Smm oldflags &= sf_mask; 2360228753Smm newflags |= oldflags; 2361228753Smm if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0) 2362228753Smm goto cleanup; 2363228753Smm } 2364228753Smm /* We couldn't set the flags, so report the failure. */ 2365228753Smmfail: 2366228753Smm archive_set_error(&a->archive, errno, 2367228753Smm "Failed to set file flags"); 2368228753Smm ret = ARCHIVE_WARN; 2369228753Smmcleanup: 2370228753Smm if (fd < 0) 2371228753Smm close(myfd); 2372228753Smm return (ret); 2373228753Smm} 2374228753Smm 2375228753Smm#else 2376228753Smm 2377228753Smm/* 2378228753Smm * Of course, some systems have neither BSD chflags() nor Linux' flags 2379228753Smm * support through ioctl(). 2380228753Smm */ 2381228753Smmstatic int 2382228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name, 2383228753Smm mode_t mode, unsigned long set, unsigned long clear) 2384228753Smm{ 2385228753Smm (void)a; /* UNUSED */ 2386228753Smm (void)fd; /* UNUSED */ 2387228753Smm (void)name; /* UNUSED */ 2388228753Smm (void)mode; /* UNUSED */ 2389228753Smm (void)set; /* UNUSED */ 2390228753Smm (void)clear; /* UNUSED */ 2391228753Smm return (ARCHIVE_OK); 2392228753Smm} 2393228753Smm 2394228753Smm#endif /* __linux */ 2395228753Smm 2396228753Smm#ifndef HAVE_POSIX_ACL 2397228753Smm/* Default empty function body to satisfy mainline code. */ 2398228753Smmstatic int 2399228753Smmset_acls(struct archive_write_disk *a) 2400228753Smm{ 2401228753Smm (void)a; /* UNUSED */ 2402228753Smm return (ARCHIVE_OK); 2403228753Smm} 2404228753Smm 2405228753Smm#else 2406228753Smm 2407228753Smm/* 2408228753Smm * XXX TODO: What about ACL types other than ACCESS and DEFAULT? 2409228753Smm */ 2410228753Smmstatic int 2411228753Smmset_acls(struct archive_write_disk *a) 2412228753Smm{ 2413228753Smm int ret; 2414228753Smm 2415228753Smm ret = set_acl(a, a->fd, a->entry, ACL_TYPE_ACCESS, 2416228753Smm ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access"); 2417228753Smm if (ret != ARCHIVE_OK) 2418228753Smm return (ret); 2419228753Smm ret = set_acl(a, a->fd, a->entry, ACL_TYPE_DEFAULT, 2420228753Smm ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); 2421228753Smm return (ret); 2422228753Smm} 2423228753Smm 2424228753Smm 2425228753Smmstatic int 2426228753Smmset_acl(struct archive_write_disk *a, int fd, struct archive_entry *entry, 2427228753Smm acl_type_t acl_type, int ae_requested_type, const char *tname) 2428228753Smm{ 2429228753Smm acl_t acl; 2430228753Smm acl_entry_t acl_entry; 2431228753Smm acl_permset_t acl_permset; 2432228753Smm int ret; 2433228753Smm int ae_type, ae_permset, ae_tag, ae_id; 2434228753Smm uid_t ae_uid; 2435228753Smm gid_t ae_gid; 2436228753Smm const char *ae_name; 2437228753Smm int entries; 2438228753Smm const char *name; 2439228753Smm 2440228753Smm ret = ARCHIVE_OK; 2441228753Smm entries = archive_entry_acl_reset(entry, ae_requested_type); 2442228753Smm if (entries == 0) 2443228753Smm return (ARCHIVE_OK); 2444228753Smm acl = acl_init(entries); 2445228753Smm while (archive_entry_acl_next(entry, ae_requested_type, &ae_type, 2446228753Smm &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { 2447228753Smm acl_create_entry(&acl, &acl_entry); 2448228753Smm 2449228753Smm switch (ae_tag) { 2450228753Smm case ARCHIVE_ENTRY_ACL_USER: 2451228753Smm acl_set_tag_type(acl_entry, ACL_USER); 2452228753Smm ae_uid = a->lookup_uid(a->lookup_uid_data, 2453228753Smm ae_name, ae_id); 2454228753Smm acl_set_qualifier(acl_entry, &ae_uid); 2455228753Smm break; 2456228753Smm case ARCHIVE_ENTRY_ACL_GROUP: 2457228753Smm acl_set_tag_type(acl_entry, ACL_GROUP); 2458228753Smm ae_gid = a->lookup_gid(a->lookup_gid_data, 2459228753Smm ae_name, ae_id); 2460228753Smm acl_set_qualifier(acl_entry, &ae_gid); 2461228753Smm break; 2462228753Smm case ARCHIVE_ENTRY_ACL_USER_OBJ: 2463228753Smm acl_set_tag_type(acl_entry, ACL_USER_OBJ); 2464228753Smm break; 2465228753Smm case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 2466228753Smm acl_set_tag_type(acl_entry, ACL_GROUP_OBJ); 2467228753Smm break; 2468228753Smm case ARCHIVE_ENTRY_ACL_MASK: 2469228753Smm acl_set_tag_type(acl_entry, ACL_MASK); 2470228753Smm break; 2471228753Smm case ARCHIVE_ENTRY_ACL_OTHER: 2472228753Smm acl_set_tag_type(acl_entry, ACL_OTHER); 2473228753Smm break; 2474228753Smm default: 2475228753Smm /* XXX */ 2476228753Smm break; 2477228753Smm } 2478228753Smm 2479228753Smm acl_get_permset(acl_entry, &acl_permset); 2480228753Smm acl_clear_perms(acl_permset); 2481228753Smm if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE) 2482228753Smm acl_add_perm(acl_permset, ACL_EXECUTE); 2483228753Smm if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE) 2484228753Smm acl_add_perm(acl_permset, ACL_WRITE); 2485228753Smm if (ae_permset & ARCHIVE_ENTRY_ACL_READ) 2486228753Smm acl_add_perm(acl_permset, ACL_READ); 2487228753Smm } 2488228753Smm 2489228753Smm name = archive_entry_pathname(entry); 2490228753Smm 2491228753Smm /* Try restoring the ACL through 'fd' if we can. */ 2492228753Smm#if HAVE_ACL_SET_FD 2493228753Smm if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0) 2494228753Smm ret = ARCHIVE_OK; 2495228753Smm else 2496228753Smm#else 2497228753Smm#if HAVE_ACL_SET_FD_NP 2498228753Smm if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0) 2499228753Smm ret = ARCHIVE_OK; 2500228753Smm else 2501228753Smm#endif 2502228753Smm#endif 2503228753Smm if (acl_set_file(name, acl_type, acl) != 0) { 2504228753Smm archive_set_error(&a->archive, errno, "Failed to set %s acl", tname); 2505228753Smm ret = ARCHIVE_WARN; 2506228753Smm } 2507228753Smm acl_free(acl); 2508228753Smm return (ret); 2509228753Smm} 2510228753Smm#endif 2511228753Smm 2512228753Smm#if HAVE_LSETXATTR 2513228753Smm/* 2514228753Smm * Restore extended attributes - Linux implementation 2515228753Smm */ 2516228753Smmstatic int 2517228753Smmset_xattrs(struct archive_write_disk *a) 2518228753Smm{ 2519228753Smm struct archive_entry *entry = a->entry; 2520228753Smm static int warning_done = 0; 2521228753Smm int ret = ARCHIVE_OK; 2522228753Smm int i = archive_entry_xattr_reset(entry); 2523228753Smm 2524228753Smm while (i--) { 2525228753Smm const char *name; 2526228753Smm const void *value; 2527228753Smm size_t size; 2528228753Smm archive_entry_xattr_next(entry, &name, &value, &size); 2529228753Smm if (name != NULL && 2530228753Smm strncmp(name, "xfsroot.", 8) != 0 && 2531228753Smm strncmp(name, "system.", 7) != 0) { 2532228753Smm int e; 2533228753Smm#if HAVE_FSETXATTR 2534228753Smm if (a->fd >= 0) 2535228753Smm e = fsetxattr(a->fd, name, value, size, 0); 2536228753Smm else 2537228753Smm#endif 2538228753Smm { 2539228753Smm e = lsetxattr(archive_entry_pathname(entry), 2540228753Smm name, value, size, 0); 2541228753Smm } 2542228753Smm if (e == -1) { 2543228753Smm if (errno == ENOTSUP) { 2544228753Smm if (!warning_done) { 2545228753Smm warning_done = 1; 2546228753Smm archive_set_error(&a->archive, errno, 2547228753Smm "Cannot restore extended " 2548228753Smm "attributes on this file " 2549228753Smm "system"); 2550228753Smm } 2551228753Smm } else 2552228753Smm archive_set_error(&a->archive, errno, 2553228753Smm "Failed to set extended attribute"); 2554228753Smm ret = ARCHIVE_WARN; 2555228753Smm } 2556228753Smm } else { 2557228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 2558228753Smm "Invalid extended attribute encountered"); 2559228753Smm ret = ARCHIVE_WARN; 2560228753Smm } 2561228753Smm } 2562228753Smm return (ret); 2563228753Smm} 2564228753Smm#elif HAVE_EXTATTR_SET_FILE && HAVE_DECL_EXTATTR_NAMESPACE_USER 2565228753Smm/* 2566228753Smm * Restore extended attributes - FreeBSD implementation 2567228753Smm */ 2568228753Smmstatic int 2569228753Smmset_xattrs(struct archive_write_disk *a) 2570228753Smm{ 2571228753Smm struct archive_entry *entry = a->entry; 2572228753Smm static int warning_done = 0; 2573228753Smm int ret = ARCHIVE_OK; 2574228753Smm int i = archive_entry_xattr_reset(entry); 2575228753Smm 2576228753Smm while (i--) { 2577228753Smm const char *name; 2578228753Smm const void *value; 2579228753Smm size_t size; 2580228753Smm archive_entry_xattr_next(entry, &name, &value, &size); 2581228753Smm if (name != NULL) { 2582228753Smm int e; 2583228753Smm int namespace; 2584228753Smm 2585228753Smm if (strncmp(name, "user.", 5) == 0) { 2586228753Smm /* "user." attributes go to user namespace */ 2587228753Smm name += 5; 2588228753Smm namespace = EXTATTR_NAMESPACE_USER; 2589228753Smm } else { 2590228753Smm /* Warn about other extended attributes. */ 2591228753Smm archive_set_error(&a->archive, 2592228753Smm ARCHIVE_ERRNO_FILE_FORMAT, 2593228753Smm "Can't restore extended attribute ``%s''", 2594228753Smm name); 2595228753Smm ret = ARCHIVE_WARN; 2596228753Smm continue; 2597228753Smm } 2598228753Smm errno = 0; 2599228753Smm#if HAVE_EXTATTR_SET_FD 2600228753Smm if (a->fd >= 0) 2601228753Smm e = extattr_set_fd(a->fd, namespace, name, value, size); 2602228753Smm else 2603228753Smm#endif 2604228753Smm /* TODO: should we use extattr_set_link() instead? */ 2605228753Smm { 2606228753Smm e = extattr_set_file(archive_entry_pathname(entry), 2607228753Smm namespace, name, value, size); 2608228753Smm } 2609228753Smm if (e != (int)size) { 2610228753Smm if (errno == ENOTSUP) { 2611228753Smm if (!warning_done) { 2612228753Smm warning_done = 1; 2613228753Smm archive_set_error(&a->archive, errno, 2614228753Smm "Cannot restore extended " 2615228753Smm "attributes on this file " 2616228753Smm "system"); 2617228753Smm } 2618228753Smm } else { 2619228753Smm archive_set_error(&a->archive, errno, 2620228753Smm "Failed to set extended attribute"); 2621228753Smm } 2622228753Smm 2623228753Smm ret = ARCHIVE_WARN; 2624228753Smm } 2625228753Smm } 2626228753Smm } 2627228753Smm return (ret); 2628228753Smm} 2629228753Smm#else 2630228753Smm/* 2631228753Smm * Restore extended attributes - stub implementation for unsupported systems 2632228753Smm */ 2633228753Smmstatic int 2634228753Smmset_xattrs(struct archive_write_disk *a) 2635228753Smm{ 2636228753Smm static int warning_done = 0; 2637228753Smm 2638228753Smm /* If there aren't any extended attributes, then it's okay not 2639228753Smm * to extract them, otherwise, issue a single warning. */ 2640228753Smm if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) { 2641228753Smm warning_done = 1; 2642228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 2643228753Smm "Cannot restore extended attributes on this system"); 2644228753Smm return (ARCHIVE_WARN); 2645228753Smm } 2646228753Smm /* Warning was already emitted; suppress further warnings. */ 2647228753Smm return (ARCHIVE_OK); 2648228753Smm} 2649228753Smm#endif 2650228753Smm 2651228753Smm 2652228753Smm/* 2653228753Smm * Trivial implementations of gid/uid lookup functions. 2654228753Smm * These are normally overridden by the client, but these stub 2655228753Smm * versions ensure that we always have something that works. 2656228753Smm */ 2657228753Smmstatic gid_t 2658228753Smmtrivial_lookup_gid(void *private_data, const char *gname, gid_t gid) 2659228753Smm{ 2660228753Smm (void)private_data; /* UNUSED */ 2661228753Smm (void)gname; /* UNUSED */ 2662228753Smm return (gid); 2663228753Smm} 2664228753Smm 2665228753Smmstatic uid_t 2666228753Smmtrivial_lookup_uid(void *private_data, const char *uname, uid_t uid) 2667228753Smm{ 2668228753Smm (void)private_data; /* UNUSED */ 2669228753Smm (void)uname; /* UNUSED */ 2670228753Smm return (uid); 2671228753Smm} 2672228753Smm 2673228753Smm/* 2674228753Smm * Test if file on disk is older than entry. 2675228753Smm */ 2676228753Smmstatic int 2677228753Smmolder(struct stat *st, struct archive_entry *entry) 2678228753Smm{ 2679228753Smm /* First, test the seconds and return if we have a definite answer. */ 2680228753Smm /* Definitely older. */ 2681228753Smm if (st->st_mtime < archive_entry_mtime(entry)) 2682228753Smm return (1); 2683228753Smm /* Definitely younger. */ 2684228753Smm if (st->st_mtime > archive_entry_mtime(entry)) 2685228753Smm return (0); 2686228753Smm /* If this platform supports fractional seconds, try those. */ 2687228753Smm#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 2688228753Smm /* Definitely older. */ 2689228753Smm if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry)) 2690228753Smm return (1); 2691228753Smm#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 2692228753Smm /* Definitely older. */ 2693228753Smm if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry)) 2694228753Smm return (1); 2695228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_N 2696228753Smm /* older. */ 2697228753Smm if (st->st_mtime_n < archive_entry_mtime_nsec(entry)) 2698228753Smm return (1); 2699228753Smm#elif HAVE_STRUCT_STAT_ST_UMTIME 2700228753Smm /* older. */ 2701228753Smm if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry)) 2702228753Smm return (1); 2703228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_USEC 2704228753Smm /* older. */ 2705228753Smm if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry)) 2706228753Smm return (1); 2707228753Smm#else 2708228753Smm /* This system doesn't have high-res timestamps. */ 2709228753Smm#endif 2710228753Smm /* Same age or newer, so not older. */ 2711228753Smm return (0); 2712228753Smm} 2713