160b4ad09SPeter Avalos /*- 260b4ad09SPeter Avalos * Copyright (c) 2003-2007 Tim Kientzle 360b4ad09SPeter Avalos * All rights reserved. 460b4ad09SPeter Avalos * 560b4ad09SPeter Avalos * Redistribution and use in source and binary forms, with or without 660b4ad09SPeter Avalos * modification, are permitted provided that the following conditions 760b4ad09SPeter Avalos * are met: 860b4ad09SPeter Avalos * 1. Redistributions of source code must retain the above copyright 960b4ad09SPeter Avalos * notice, this list of conditions and the following disclaimer 1060b4ad09SPeter Avalos * in this position and unchanged. 1160b4ad09SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1260b4ad09SPeter Avalos * notice, this list of conditions and the following disclaimer in the 1360b4ad09SPeter Avalos * documentation and/or other materials provided with the distribution. 1460b4ad09SPeter Avalos * 1560b4ad09SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 1660b4ad09SPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1760b4ad09SPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1860b4ad09SPeter Avalos * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 1960b4ad09SPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2060b4ad09SPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2160b4ad09SPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2260b4ad09SPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2360b4ad09SPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2460b4ad09SPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2560b4ad09SPeter Avalos */ 2660b4ad09SPeter Avalos 2760b4ad09SPeter Avalos 2860b4ad09SPeter Avalos #include "cpio_platform.h" 298029ab02SPeter Avalos __FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.15 2008/12/06 07:30:40 kientzle Exp $"); 3060b4ad09SPeter Avalos 3160b4ad09SPeter Avalos #include <sys/types.h> 3260b4ad09SPeter Avalos #include <archive.h> 3360b4ad09SPeter Avalos #include <archive_entry.h> 3460b4ad09SPeter Avalos 358029ab02SPeter Avalos #ifdef HAVE_SYS_MKDEV_H 368029ab02SPeter Avalos #include <sys/mkdev.h> 378029ab02SPeter Avalos #endif 3860b4ad09SPeter Avalos #ifdef HAVE_SYS_STAT_H 3960b4ad09SPeter Avalos #include <sys/stat.h> 4060b4ad09SPeter Avalos #endif 418029ab02SPeter Avalos #ifdef HAVE_SYS_TIME_H 428029ab02SPeter Avalos #include <sys/time.h> 438029ab02SPeter Avalos #endif 4460b4ad09SPeter Avalos #ifdef HAVE_ERRNO_H 4560b4ad09SPeter Avalos #include <errno.h> 4660b4ad09SPeter Avalos #endif 4760b4ad09SPeter Avalos #ifdef HAVE_FCNTL_H 4860b4ad09SPeter Avalos #include <fcntl.h> 4960b4ad09SPeter Avalos #endif 508029ab02SPeter Avalos #ifdef HAVE_GRP_H 518029ab02SPeter Avalos #include <grp.h> 528029ab02SPeter Avalos #endif 53c09f92d2SPeter Avalos #ifdef HAVE_LOCALE_H 54c09f92d2SPeter Avalos #include <locale.h> 55c09f92d2SPeter Avalos #endif 568029ab02SPeter Avalos #ifdef HAVE_PWD_H 578029ab02SPeter Avalos #include <pwd.h> 588029ab02SPeter Avalos #endif 59c09f92d2SPeter Avalos #ifdef HAVE_SIGNAL_H 60c09f92d2SPeter Avalos #include <signal.h> 61c09f92d2SPeter Avalos #endif 6260b4ad09SPeter Avalos #ifdef HAVE_STDARG_H 6360b4ad09SPeter Avalos #include <stdarg.h> 6460b4ad09SPeter Avalos #endif 659c82a63eSPeter Avalos #ifdef HAVE_STDINT_H 669c82a63eSPeter Avalos #include <stdint.h> 679c82a63eSPeter Avalos #endif 6860b4ad09SPeter Avalos #include <stdio.h> 6960b4ad09SPeter Avalos #ifdef HAVE_STDLIB_H 7060b4ad09SPeter Avalos #include <stdlib.h> 7160b4ad09SPeter Avalos #endif 7260b4ad09SPeter Avalos #ifdef HAVE_STRING_H 7360b4ad09SPeter Avalos #include <string.h> 7460b4ad09SPeter Avalos #endif 7560b4ad09SPeter Avalos #ifdef HAVE_UNISTD_H 7660b4ad09SPeter Avalos #include <unistd.h> 7760b4ad09SPeter Avalos #endif 788029ab02SPeter Avalos #ifdef HAVE_TIME_H 798029ab02SPeter Avalos #include <time.h> 808029ab02SPeter Avalos #endif 8160b4ad09SPeter Avalos 8260b4ad09SPeter Avalos #include "cpio.h" 839c82a63eSPeter Avalos #include "err.h" 849c82a63eSPeter Avalos #include "line_reader.h" 85*6b384f39SPeter Avalos #include "passphrase.h" 8660b4ad09SPeter Avalos 878029ab02SPeter Avalos /* Fixed size of uname/gname caches. */ 888029ab02SPeter Avalos #define name_cache_size 101 898029ab02SPeter Avalos 909c82a63eSPeter Avalos #ifndef O_BINARY 919c82a63eSPeter Avalos #define O_BINARY 0 929c82a63eSPeter Avalos #endif 939c82a63eSPeter Avalos 948029ab02SPeter Avalos struct name_cache { 958029ab02SPeter Avalos int probes; 968029ab02SPeter Avalos int hits; 978029ab02SPeter Avalos size_t size; 988029ab02SPeter Avalos struct { 998029ab02SPeter Avalos id_t id; 1008029ab02SPeter Avalos char *name; 1018029ab02SPeter Avalos } cache[name_cache_size]; 1028029ab02SPeter Avalos }; 1038029ab02SPeter Avalos 1049c82a63eSPeter Avalos static int extract_data(struct archive *, struct archive *); 1059c82a63eSPeter Avalos const char * cpio_i64toa(int64_t); 10660b4ad09SPeter Avalos static const char *cpio_rename(const char *name); 10760b4ad09SPeter Avalos static int entry_to_archive(struct cpio *, struct archive_entry *); 10860b4ad09SPeter Avalos static int file_to_archive(struct cpio *, const char *); 1098029ab02SPeter Avalos static void free_cache(struct name_cache *cache); 1108029ab02SPeter Avalos static void list_item_verbose(struct cpio *, struct archive_entry *); 11160b4ad09SPeter Avalos static void long_help(void); 1128029ab02SPeter Avalos static const char *lookup_gname(struct cpio *, gid_t gid); 1138029ab02SPeter Avalos static int lookup_gname_helper(struct cpio *, 1148029ab02SPeter Avalos const char **name, id_t gid); 1158029ab02SPeter Avalos static const char *lookup_uname(struct cpio *, uid_t uid); 1168029ab02SPeter Avalos static int lookup_uname_helper(struct cpio *, 1178029ab02SPeter Avalos const char **name, id_t uid); 11860b4ad09SPeter Avalos static void mode_in(struct cpio *); 11960b4ad09SPeter Avalos static void mode_list(struct cpio *); 12060b4ad09SPeter Avalos static void mode_out(struct cpio *); 12160b4ad09SPeter Avalos static void mode_pass(struct cpio *, const char *); 12259bf7050SPeter Avalos static const char *remove_leading_slash(const char *); 1238029ab02SPeter Avalos static int restore_time(struct cpio *, struct archive_entry *, 12460b4ad09SPeter Avalos const char *, int fd); 12560b4ad09SPeter Avalos static void usage(void); 12660b4ad09SPeter Avalos static void version(void); 127*6b384f39SPeter Avalos static const char * passphrase_callback(struct archive *, void *); 128*6b384f39SPeter Avalos static void passphrase_free(char *); 12960b4ad09SPeter Avalos 13060b4ad09SPeter Avalos int 13160b4ad09SPeter Avalos main(int argc, char *argv[]) 13260b4ad09SPeter Avalos { 13360b4ad09SPeter Avalos static char buff[16384]; 13460b4ad09SPeter Avalos struct cpio _cpio; /* Allocated on stack. */ 13560b4ad09SPeter Avalos struct cpio *cpio; 1369c82a63eSPeter Avalos const char *errmsg; 13760b4ad09SPeter Avalos int uid, gid; 13860b4ad09SPeter Avalos int opt; 13960b4ad09SPeter Avalos 14060b4ad09SPeter Avalos cpio = &_cpio; 14160b4ad09SPeter Avalos memset(cpio, 0, sizeof(*cpio)); 14260b4ad09SPeter Avalos cpio->buff = buff; 14360b4ad09SPeter Avalos cpio->buff_size = sizeof(buff); 14460b4ad09SPeter Avalos 145c09f92d2SPeter Avalos #if defined(HAVE_SIGACTION) && defined(SIGPIPE) 146c09f92d2SPeter Avalos { /* Ignore SIGPIPE signals. */ 147c09f92d2SPeter Avalos struct sigaction sa; 148c09f92d2SPeter Avalos sigemptyset(&sa.sa_mask); 149c09f92d2SPeter Avalos sa.sa_flags = 0; 150c09f92d2SPeter Avalos sa.sa_handler = SIG_IGN; 151c09f92d2SPeter Avalos sigaction(SIGPIPE, &sa, NULL); 152c09f92d2SPeter Avalos } 153c09f92d2SPeter Avalos #endif 154c09f92d2SPeter Avalos 155*6b384f39SPeter Avalos /* Set lafe_progname before calling lafe_warnc. */ 156*6b384f39SPeter Avalos lafe_setprogname(*argv, "bsdcpio"); 157*6b384f39SPeter Avalos 158c09f92d2SPeter Avalos #if HAVE_SETLOCALE 159c09f92d2SPeter Avalos if (setlocale(LC_ALL, "") == NULL) 160c09f92d2SPeter Avalos lafe_warnc(0, "Failed to set default locale"); 161c09f92d2SPeter Avalos #endif 16260b4ad09SPeter Avalos 16360b4ad09SPeter Avalos cpio->uid_override = -1; 16460b4ad09SPeter Avalos cpio->gid_override = -1; 16560b4ad09SPeter Avalos cpio->argv = argv; 16660b4ad09SPeter Avalos cpio->argc = argc; 16760b4ad09SPeter Avalos cpio->mode = '\0'; 16860b4ad09SPeter Avalos cpio->verbose = 0; 16960b4ad09SPeter Avalos cpio->compress = '\0'; 17060b4ad09SPeter Avalos cpio->extract_flags = ARCHIVE_EXTRACT_NO_AUTODIR; 17160b4ad09SPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; 17260b4ad09SPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS; 17360b4ad09SPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT; 174*6b384f39SPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS; 1758029ab02SPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_PERM; 1768029ab02SPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; 1778029ab02SPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_ACL; 1789c82a63eSPeter Avalos #if !defined(_WIN32) && !defined(__CYGWIN__) 1798029ab02SPeter Avalos if (geteuid() == 0) 1808029ab02SPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; 1819c82a63eSPeter Avalos #endif 18260b4ad09SPeter Avalos cpio->bytes_per_block = 512; 18360b4ad09SPeter Avalos cpio->filename = NULL; 18460b4ad09SPeter Avalos 18559bf7050SPeter Avalos cpio->matching = archive_match_new(); 18659bf7050SPeter Avalos if (cpio->matching == NULL) 18759bf7050SPeter Avalos lafe_errc(1, 0, "Out of memory"); 18859bf7050SPeter Avalos 18960b4ad09SPeter Avalos while ((opt = cpio_getopt(cpio)) != -1) { 19060b4ad09SPeter Avalos switch (opt) { 19160b4ad09SPeter Avalos case '0': /* GNU convention: --null, -0 */ 1929c82a63eSPeter Avalos cpio->option_null = 1; 19360b4ad09SPeter Avalos break; 19460b4ad09SPeter Avalos case 'A': /* NetBSD/OpenBSD */ 19560b4ad09SPeter Avalos cpio->option_append = 1; 19660b4ad09SPeter Avalos break; 19760b4ad09SPeter Avalos case 'a': /* POSIX 1997 */ 19860b4ad09SPeter Avalos cpio->option_atime_restore = 1; 19960b4ad09SPeter Avalos break; 20060b4ad09SPeter Avalos case 'B': /* POSIX 1997 */ 20160b4ad09SPeter Avalos cpio->bytes_per_block = 5120; 20260b4ad09SPeter Avalos break; 203d4d8193eSPeter Avalos case OPTION_B64ENCODE: 204d4d8193eSPeter Avalos cpio->add_filter = opt; 205d4d8193eSPeter Avalos break; 20660b4ad09SPeter Avalos case 'C': /* NetBSD/OpenBSD */ 207c09f92d2SPeter Avalos cpio->bytes_per_block = atoi(cpio->argument); 20860b4ad09SPeter Avalos if (cpio->bytes_per_block <= 0) 209c09f92d2SPeter Avalos lafe_errc(1, 0, "Invalid blocksize %s", cpio->argument); 21060b4ad09SPeter Avalos break; 21160b4ad09SPeter Avalos case 'c': /* POSIX 1997 */ 21260b4ad09SPeter Avalos cpio->format = "odc"; 21360b4ad09SPeter Avalos break; 21460b4ad09SPeter Avalos case 'd': /* POSIX 1997 */ 21560b4ad09SPeter Avalos cpio->extract_flags &= ~ARCHIVE_EXTRACT_NO_AUTODIR; 21660b4ad09SPeter Avalos break; 21760b4ad09SPeter Avalos case 'E': /* NetBSD/OpenBSD */ 21859bf7050SPeter Avalos if (archive_match_include_pattern_from_file( 21959bf7050SPeter Avalos cpio->matching, cpio->argument, 22059bf7050SPeter Avalos cpio->option_null) != ARCHIVE_OK) 22159bf7050SPeter Avalos lafe_errc(1, 0, "Error : %s", 22259bf7050SPeter Avalos archive_error_string(cpio->matching)); 22360b4ad09SPeter Avalos break; 22460b4ad09SPeter Avalos case 'F': /* NetBSD/OpenBSD/GNU cpio */ 225c09f92d2SPeter Avalos cpio->filename = cpio->argument; 22660b4ad09SPeter Avalos break; 22760b4ad09SPeter Avalos case 'f': /* POSIX 1997 */ 22859bf7050SPeter Avalos if (archive_match_exclude_pattern(cpio->matching, 22959bf7050SPeter Avalos cpio->argument) != ARCHIVE_OK) 23059bf7050SPeter Avalos lafe_errc(1, 0, "Error : %s", 23159bf7050SPeter Avalos archive_error_string(cpio->matching)); 23260b4ad09SPeter Avalos break; 233d4d8193eSPeter Avalos case OPTION_GRZIP: 234d4d8193eSPeter Avalos cpio->compress = opt; 235d4d8193eSPeter Avalos break; 23660b4ad09SPeter Avalos case 'H': /* GNU cpio (also --format) */ 237c09f92d2SPeter Avalos cpio->format = cpio->argument; 23860b4ad09SPeter Avalos break; 23960b4ad09SPeter Avalos case 'h': 24060b4ad09SPeter Avalos long_help(); 24160b4ad09SPeter Avalos break; 24260b4ad09SPeter Avalos case 'I': /* NetBSD/OpenBSD */ 243c09f92d2SPeter Avalos cpio->filename = cpio->argument; 24460b4ad09SPeter Avalos break; 24560b4ad09SPeter Avalos case 'i': /* POSIX 1997 */ 2468029ab02SPeter Avalos if (cpio->mode != '\0') 2479c82a63eSPeter Avalos lafe_errc(1, 0, 2488029ab02SPeter Avalos "Cannot use both -i and -%c", cpio->mode); 24960b4ad09SPeter Avalos cpio->mode = opt; 25060b4ad09SPeter Avalos break; 2519c82a63eSPeter Avalos case 'J': /* GNU tar, others */ 2529c82a63eSPeter Avalos cpio->compress = opt; 2539c82a63eSPeter Avalos break; 2549c82a63eSPeter Avalos case 'j': /* GNU tar, others */ 2559c82a63eSPeter Avalos cpio->compress = opt; 2569c82a63eSPeter Avalos break; 25760b4ad09SPeter Avalos case OPTION_INSECURE: 25860b4ad09SPeter Avalos cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_SYMLINKS; 25960b4ad09SPeter Avalos cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; 260*6b384f39SPeter Avalos cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS; 26160b4ad09SPeter Avalos break; 26260b4ad09SPeter Avalos case 'L': /* GNU cpio */ 26360b4ad09SPeter Avalos cpio->option_follow_links = 1; 26460b4ad09SPeter Avalos break; 26560b4ad09SPeter Avalos case 'l': /* POSIX 1997 */ 26660b4ad09SPeter Avalos cpio->option_link = 1; 26760b4ad09SPeter Avalos break; 268d4d8193eSPeter Avalos case OPTION_LRZIP: 269*6b384f39SPeter Avalos case OPTION_LZ4: 2709c82a63eSPeter Avalos case OPTION_LZMA: /* GNU tar, others */ 271d4d8193eSPeter Avalos case OPTION_LZOP: /* GNU tar, others */ 2729c82a63eSPeter Avalos cpio->compress = opt; 2739c82a63eSPeter Avalos break; 27460b4ad09SPeter Avalos case 'm': /* POSIX 1997 */ 27560b4ad09SPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_TIME; 27660b4ad09SPeter Avalos break; 2778029ab02SPeter Avalos case 'n': /* GNU cpio */ 2788029ab02SPeter Avalos cpio->option_numeric_uid_gid = 1; 2798029ab02SPeter Avalos break; 2808029ab02SPeter Avalos case OPTION_NO_PRESERVE_OWNER: /* GNU cpio */ 2818029ab02SPeter Avalos cpio->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; 2828029ab02SPeter Avalos break; 28360b4ad09SPeter Avalos case 'O': /* GNU cpio */ 284c09f92d2SPeter Avalos cpio->filename = cpio->argument; 28560b4ad09SPeter Avalos break; 28660b4ad09SPeter Avalos case 'o': /* POSIX 1997 */ 2878029ab02SPeter Avalos if (cpio->mode != '\0') 2889c82a63eSPeter Avalos lafe_errc(1, 0, 2898029ab02SPeter Avalos "Cannot use both -o and -%c", cpio->mode); 29060b4ad09SPeter Avalos cpio->mode = opt; 29160b4ad09SPeter Avalos break; 29260b4ad09SPeter Avalos case 'p': /* POSIX 1997 */ 2938029ab02SPeter Avalos if (cpio->mode != '\0') 2949c82a63eSPeter Avalos lafe_errc(1, 0, 2958029ab02SPeter Avalos "Cannot use both -p and -%c", cpio->mode); 29660b4ad09SPeter Avalos cpio->mode = opt; 29760b4ad09SPeter Avalos cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; 29860b4ad09SPeter Avalos break; 299*6b384f39SPeter Avalos case OPTION_PASSPHRASE: 300*6b384f39SPeter Avalos cpio->passphrase = cpio->argument; 301*6b384f39SPeter Avalos break; 3029c82a63eSPeter Avalos case OPTION_PRESERVE_OWNER: 3039c82a63eSPeter Avalos cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; 3049c82a63eSPeter Avalos break; 30560b4ad09SPeter Avalos case OPTION_QUIET: /* GNU cpio */ 30660b4ad09SPeter Avalos cpio->quiet = 1; 30760b4ad09SPeter Avalos break; 30860b4ad09SPeter Avalos case 'R': /* GNU cpio, also --owner */ 309c09f92d2SPeter Avalos /* TODO: owner_parse should return uname/gname 310c09f92d2SPeter Avalos * also; use that to set [ug]name_override. */ 311c09f92d2SPeter Avalos errmsg = owner_parse(cpio->argument, &uid, &gid); 3129c82a63eSPeter Avalos if (errmsg) { 3139c82a63eSPeter Avalos lafe_warnc(-1, "%s", errmsg); 31460b4ad09SPeter Avalos usage(); 3159c82a63eSPeter Avalos } 316c09f92d2SPeter Avalos if (uid != -1) { 31760b4ad09SPeter Avalos cpio->uid_override = uid; 318c09f92d2SPeter Avalos cpio->uname_override = NULL; 319c09f92d2SPeter Avalos } 320c09f92d2SPeter Avalos if (gid != -1) { 32160b4ad09SPeter Avalos cpio->gid_override = gid; 322c09f92d2SPeter Avalos cpio->gname_override = NULL; 323c09f92d2SPeter Avalos } 32460b4ad09SPeter Avalos break; 32560b4ad09SPeter Avalos case 'r': /* POSIX 1997 */ 32660b4ad09SPeter Avalos cpio->option_rename = 1; 32760b4ad09SPeter Avalos break; 32860b4ad09SPeter Avalos case 't': /* POSIX 1997 */ 32960b4ad09SPeter Avalos cpio->option_list = 1; 33060b4ad09SPeter Avalos break; 33160b4ad09SPeter Avalos case 'u': /* POSIX 1997 */ 33260b4ad09SPeter Avalos cpio->extract_flags 33360b4ad09SPeter Avalos &= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; 33460b4ad09SPeter Avalos break; 335d4d8193eSPeter Avalos case OPTION_UUENCODE: 336d4d8193eSPeter Avalos cpio->add_filter = opt; 337d4d8193eSPeter Avalos break; 33860b4ad09SPeter Avalos case 'v': /* POSIX 1997 */ 33960b4ad09SPeter Avalos cpio->verbose++; 34060b4ad09SPeter Avalos break; 341c09f92d2SPeter Avalos case 'V': /* GNU cpio */ 342c09f92d2SPeter Avalos cpio->dot++; 343c09f92d2SPeter Avalos break; 34460b4ad09SPeter Avalos case OPTION_VERSION: /* GNU convention */ 34560b4ad09SPeter Avalos version(); 34660b4ad09SPeter Avalos break; 34760b4ad09SPeter Avalos #if 0 34860b4ad09SPeter Avalos /* 34960b4ad09SPeter Avalos * cpio_getopt() handles -W specially, so it's not 35060b4ad09SPeter Avalos * available here. 35160b4ad09SPeter Avalos */ 35260b4ad09SPeter Avalos case 'W': /* Obscure, but useful GNU convention. */ 35360b4ad09SPeter Avalos break; 35460b4ad09SPeter Avalos #endif 35560b4ad09SPeter Avalos case 'y': /* tar convention */ 35660b4ad09SPeter Avalos cpio->compress = opt; 35760b4ad09SPeter Avalos break; 35860b4ad09SPeter Avalos case 'Z': /* tar convention */ 35960b4ad09SPeter Avalos cpio->compress = opt; 36060b4ad09SPeter Avalos break; 36160b4ad09SPeter Avalos case 'z': /* tar convention */ 36260b4ad09SPeter Avalos cpio->compress = opt; 36360b4ad09SPeter Avalos break; 36460b4ad09SPeter Avalos default: 36560b4ad09SPeter Avalos usage(); 36660b4ad09SPeter Avalos } 36760b4ad09SPeter Avalos } 36860b4ad09SPeter Avalos 3698029ab02SPeter Avalos /* 3708029ab02SPeter Avalos * Sanity-check args, error out on nonsensical combinations. 3718029ab02SPeter Avalos */ 3728029ab02SPeter Avalos /* -t implies -i if no mode was specified. */ 3738029ab02SPeter Avalos if (cpio->option_list && cpio->mode == '\0') 3748029ab02SPeter Avalos cpio->mode = 'i'; 3758029ab02SPeter Avalos /* -t requires -i */ 3768029ab02SPeter Avalos if (cpio->option_list && cpio->mode != 'i') 3779c82a63eSPeter Avalos lafe_errc(1, 0, "Option -t requires -i"); 3788029ab02SPeter Avalos /* -n requires -it */ 3798029ab02SPeter Avalos if (cpio->option_numeric_uid_gid && !cpio->option_list) 3809c82a63eSPeter Avalos lafe_errc(1, 0, "Option -n requires -it"); 3818029ab02SPeter Avalos /* Can only specify format when writing */ 3828029ab02SPeter Avalos if (cpio->format != NULL && cpio->mode != 'o') 3839c82a63eSPeter Avalos lafe_errc(1, 0, "Option --format requires -o"); 3848029ab02SPeter Avalos /* -l requires -p */ 3858029ab02SPeter Avalos if (cpio->option_link && cpio->mode != 'p') 3869c82a63eSPeter Avalos lafe_errc(1, 0, "Option -l requires -p"); 387c09f92d2SPeter Avalos /* -v overrides -V */ 388c09f92d2SPeter Avalos if (cpio->dot && cpio->verbose) 389c09f92d2SPeter Avalos cpio->dot = 0; 3908029ab02SPeter Avalos /* TODO: Flag other nonsensical combinations. */ 39160b4ad09SPeter Avalos 39260b4ad09SPeter Avalos switch (cpio->mode) { 39360b4ad09SPeter Avalos case 'o': 3948029ab02SPeter Avalos /* TODO: Implement old binary format in libarchive, 3958029ab02SPeter Avalos use that here. */ 3968029ab02SPeter Avalos if (cpio->format == NULL) 3978029ab02SPeter Avalos cpio->format = "odc"; /* Default format */ 3988029ab02SPeter Avalos 39960b4ad09SPeter Avalos mode_out(cpio); 40060b4ad09SPeter Avalos break; 40160b4ad09SPeter Avalos case 'i': 40260b4ad09SPeter Avalos while (*cpio->argv != NULL) { 40359bf7050SPeter Avalos if (archive_match_include_pattern(cpio->matching, 40459bf7050SPeter Avalos *cpio->argv) != ARCHIVE_OK) 40559bf7050SPeter Avalos lafe_errc(1, 0, "Error : %s", 40659bf7050SPeter Avalos archive_error_string(cpio->matching)); 40760b4ad09SPeter Avalos --cpio->argc; 40860b4ad09SPeter Avalos ++cpio->argv; 40960b4ad09SPeter Avalos } 41060b4ad09SPeter Avalos if (cpio->option_list) 41160b4ad09SPeter Avalos mode_list(cpio); 41260b4ad09SPeter Avalos else 41360b4ad09SPeter Avalos mode_in(cpio); 41460b4ad09SPeter Avalos break; 41560b4ad09SPeter Avalos case 'p': 41660b4ad09SPeter Avalos if (*cpio->argv == NULL || **cpio->argv == '\0') 4179c82a63eSPeter Avalos lafe_errc(1, 0, 41860b4ad09SPeter Avalos "-p mode requires a target directory"); 41960b4ad09SPeter Avalos mode_pass(cpio, *cpio->argv); 42060b4ad09SPeter Avalos break; 42160b4ad09SPeter Avalos default: 4229c82a63eSPeter Avalos lafe_errc(1, 0, 42360b4ad09SPeter Avalos "Must specify at least one of -i, -o, or -p"); 42460b4ad09SPeter Avalos } 42560b4ad09SPeter Avalos 42659bf7050SPeter Avalos archive_match_free(cpio->matching); 4278029ab02SPeter Avalos free_cache(cpio->gname_cache); 4288029ab02SPeter Avalos free_cache(cpio->uname_cache); 429d4d8193eSPeter Avalos free(cpio->destdir); 430*6b384f39SPeter Avalos passphrase_free(cpio->ppbuff); 4319c82a63eSPeter Avalos return (cpio->return_value); 43260b4ad09SPeter Avalos } 43360b4ad09SPeter Avalos 4349c82a63eSPeter Avalos static void 43560b4ad09SPeter Avalos usage(void) 43660b4ad09SPeter Avalos { 43760b4ad09SPeter Avalos const char *p; 43860b4ad09SPeter Avalos 439*6b384f39SPeter Avalos p = lafe_getprogname(); 44060b4ad09SPeter Avalos 44160b4ad09SPeter Avalos fprintf(stderr, "Brief Usage:\n"); 44260b4ad09SPeter Avalos fprintf(stderr, " List: %s -it < archive\n", p); 44360b4ad09SPeter Avalos fprintf(stderr, " Extract: %s -i < archive\n", p); 44460b4ad09SPeter Avalos fprintf(stderr, " Create: %s -o < filenames > archive\n", p); 44560b4ad09SPeter Avalos fprintf(stderr, " Help: %s --help\n", p); 44660b4ad09SPeter Avalos exit(1); 44760b4ad09SPeter Avalos } 44860b4ad09SPeter Avalos 44960b4ad09SPeter Avalos static const char *long_help_msg = 45060b4ad09SPeter Avalos "First option must be a mode specifier:\n" 45160b4ad09SPeter Avalos " -i Input -o Output -p Pass\n" 45260b4ad09SPeter Avalos "Common Options:\n" 453c09f92d2SPeter Avalos " -v Verbose filenames -V one dot per file\n" 45460b4ad09SPeter Avalos "Create: %p -o [options] < [list of files] > [archive]\n" 4559c82a63eSPeter Avalos " -J,-y,-z,--lzma Compress archive with xz/bzip2/gzip/lzma\n" 45660b4ad09SPeter Avalos " --format {odc|newc|ustar} Select archive format\n" 45760b4ad09SPeter Avalos "List: %p -it < [archive]\n" 45860b4ad09SPeter Avalos "Extract: %p -i [options] < [archive]\n"; 45960b4ad09SPeter Avalos 46060b4ad09SPeter Avalos 46160b4ad09SPeter Avalos /* 46260b4ad09SPeter Avalos * Note that the word 'bsdcpio' will always appear in the first line 46360b4ad09SPeter Avalos * of output. 46460b4ad09SPeter Avalos * 46560b4ad09SPeter Avalos * In particular, /bin/sh scripts that need to test for the presence 46660b4ad09SPeter Avalos * of bsdcpio can use the following template: 46760b4ad09SPeter Avalos * 46860b4ad09SPeter Avalos * if (cpio --help 2>&1 | grep bsdcpio >/dev/null 2>&1 ) then \ 46960b4ad09SPeter Avalos * echo bsdcpio; else echo not bsdcpio; fi 47060b4ad09SPeter Avalos */ 47160b4ad09SPeter Avalos static void 47260b4ad09SPeter Avalos long_help(void) 47360b4ad09SPeter Avalos { 47460b4ad09SPeter Avalos const char *prog; 47560b4ad09SPeter Avalos const char *p; 47660b4ad09SPeter Avalos 477*6b384f39SPeter Avalos prog = lafe_getprogname(); 47860b4ad09SPeter Avalos 47960b4ad09SPeter Avalos fflush(stderr); 48060b4ad09SPeter Avalos 48160b4ad09SPeter Avalos p = (strcmp(prog,"bsdcpio") != 0) ? "(bsdcpio)" : ""; 48260b4ad09SPeter Avalos printf("%s%s: manipulate archive files\n", prog, p); 48360b4ad09SPeter Avalos 48460b4ad09SPeter Avalos for (p = long_help_msg; *p != '\0'; p++) { 48560b4ad09SPeter Avalos if (*p == '%') { 48660b4ad09SPeter Avalos if (p[1] == 'p') { 48760b4ad09SPeter Avalos fputs(prog, stdout); 48860b4ad09SPeter Avalos p++; 48960b4ad09SPeter Avalos } else 49060b4ad09SPeter Avalos putchar('%'); 49160b4ad09SPeter Avalos } else 49260b4ad09SPeter Avalos putchar(*p); 49360b4ad09SPeter Avalos } 49460b4ad09SPeter Avalos version(); 49560b4ad09SPeter Avalos } 49660b4ad09SPeter Avalos 49760b4ad09SPeter Avalos static void 49860b4ad09SPeter Avalos version(void) 49960b4ad09SPeter Avalos { 50060b4ad09SPeter Avalos fprintf(stdout,"bsdcpio %s -- %s\n", 50160b4ad09SPeter Avalos BSDCPIO_VERSION_STRING, 502*6b384f39SPeter Avalos archive_version_details()); 50360b4ad09SPeter Avalos exit(0); 50460b4ad09SPeter Avalos } 50560b4ad09SPeter Avalos 50660b4ad09SPeter Avalos static void 50760b4ad09SPeter Avalos mode_out(struct cpio *cpio) 50860b4ad09SPeter Avalos { 50960b4ad09SPeter Avalos struct archive_entry *entry, *spare; 5109c82a63eSPeter Avalos struct lafe_line_reader *lr; 51160b4ad09SPeter Avalos const char *p; 51260b4ad09SPeter Avalos int r; 51360b4ad09SPeter Avalos 51460b4ad09SPeter Avalos if (cpio->option_append) 5159c82a63eSPeter Avalos lafe_errc(1, 0, "Append mode not yet supported."); 5169c82a63eSPeter Avalos 5179c82a63eSPeter Avalos cpio->archive_read_disk = archive_read_disk_new(); 5189c82a63eSPeter Avalos if (cpio->archive_read_disk == NULL) 5199c82a63eSPeter Avalos lafe_errc(1, 0, "Failed to allocate archive object"); 5209c82a63eSPeter Avalos if (cpio->option_follow_links) 5219c82a63eSPeter Avalos archive_read_disk_set_symlink_logical(cpio->archive_read_disk); 5229c82a63eSPeter Avalos else 5239c82a63eSPeter Avalos archive_read_disk_set_symlink_physical(cpio->archive_read_disk); 5249c82a63eSPeter Avalos archive_read_disk_set_standard_lookup(cpio->archive_read_disk); 5259c82a63eSPeter Avalos 52660b4ad09SPeter Avalos cpio->archive = archive_write_new(); 52760b4ad09SPeter Avalos if (cpio->archive == NULL) 5289c82a63eSPeter Avalos lafe_errc(1, 0, "Failed to allocate archive object"); 52960b4ad09SPeter Avalos switch (cpio->compress) { 530d4d8193eSPeter Avalos case OPTION_GRZIP: 531d4d8193eSPeter Avalos r = archive_write_add_filter_grzip(cpio->archive); 532d4d8193eSPeter Avalos break; 5339c82a63eSPeter Avalos case 'J': 534d4d8193eSPeter Avalos r = archive_write_add_filter_xz(cpio->archive); 535d4d8193eSPeter Avalos break; 536d4d8193eSPeter Avalos case OPTION_LRZIP: 537d4d8193eSPeter Avalos r = archive_write_add_filter_lrzip(cpio->archive); 5389c82a63eSPeter Avalos break; 539*6b384f39SPeter Avalos case OPTION_LZ4: 540*6b384f39SPeter Avalos r = archive_write_add_filter_lz4(cpio->archive); 541*6b384f39SPeter Avalos break; 5429c82a63eSPeter Avalos case OPTION_LZMA: 543d4d8193eSPeter Avalos r = archive_write_add_filter_lzma(cpio->archive); 544d4d8193eSPeter Avalos break; 545d4d8193eSPeter Avalos case OPTION_LZOP: 546d4d8193eSPeter Avalos r = archive_write_add_filter_lzop(cpio->archive); 5479c82a63eSPeter Avalos break; 54860b4ad09SPeter Avalos case 'j': case 'y': 549d4d8193eSPeter Avalos r = archive_write_add_filter_bzip2(cpio->archive); 55060b4ad09SPeter Avalos break; 55160b4ad09SPeter Avalos case 'z': 552d4d8193eSPeter Avalos r = archive_write_add_filter_gzip(cpio->archive); 55360b4ad09SPeter Avalos break; 55460b4ad09SPeter Avalos case 'Z': 555d4d8193eSPeter Avalos r = archive_write_add_filter_compress(cpio->archive); 55660b4ad09SPeter Avalos break; 55760b4ad09SPeter Avalos default: 558d4d8193eSPeter Avalos r = archive_write_add_filter_none(cpio->archive); 55960b4ad09SPeter Avalos break; 56060b4ad09SPeter Avalos } 5619c82a63eSPeter Avalos if (r < ARCHIVE_WARN) 5629c82a63eSPeter Avalos lafe_errc(1, 0, "Requested compression not available"); 563d4d8193eSPeter Avalos switch (cpio->add_filter) { 564d4d8193eSPeter Avalos case 0: 565d4d8193eSPeter Avalos r = ARCHIVE_OK; 566d4d8193eSPeter Avalos break; 567d4d8193eSPeter Avalos case OPTION_B64ENCODE: 568d4d8193eSPeter Avalos r = archive_write_add_filter_b64encode(cpio->archive); 569d4d8193eSPeter Avalos break; 570d4d8193eSPeter Avalos case OPTION_UUENCODE: 571d4d8193eSPeter Avalos r = archive_write_add_filter_uuencode(cpio->archive); 572d4d8193eSPeter Avalos break; 573d4d8193eSPeter Avalos } 574d4d8193eSPeter Avalos if (r < ARCHIVE_WARN) 575d4d8193eSPeter Avalos lafe_errc(1, 0, "Requested filter not available"); 57660b4ad09SPeter Avalos r = archive_write_set_format_by_name(cpio->archive, cpio->format); 57760b4ad09SPeter Avalos if (r != ARCHIVE_OK) 5789c82a63eSPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); 57960b4ad09SPeter Avalos archive_write_set_bytes_per_block(cpio->archive, cpio->bytes_per_block); 58060b4ad09SPeter Avalos cpio->linkresolver = archive_entry_linkresolver_new(); 58160b4ad09SPeter Avalos archive_entry_linkresolver_set_strategy(cpio->linkresolver, 58260b4ad09SPeter Avalos archive_format(cpio->archive)); 583*6b384f39SPeter Avalos if (cpio->passphrase != NULL) 584*6b384f39SPeter Avalos r = archive_write_set_passphrase(cpio->archive, 585*6b384f39SPeter Avalos cpio->passphrase); 586*6b384f39SPeter Avalos else 587*6b384f39SPeter Avalos r = archive_write_set_passphrase_callback(cpio->archive, cpio, 588*6b384f39SPeter Avalos &passphrase_callback); 589*6b384f39SPeter Avalos if (r != ARCHIVE_OK) 590*6b384f39SPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); 59160b4ad09SPeter Avalos 5929c82a63eSPeter Avalos /* 5939c82a63eSPeter Avalos * The main loop: Copy each file into the output archive. 5949c82a63eSPeter Avalos */ 595d4d8193eSPeter Avalos r = archive_write_open_filename(cpio->archive, cpio->filename); 59660b4ad09SPeter Avalos if (r != ARCHIVE_OK) 5979c82a63eSPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); 5989c82a63eSPeter Avalos lr = lafe_line_reader("-", cpio->option_null); 5999c82a63eSPeter Avalos while ((p = lafe_line_reader_next(lr)) != NULL) 60060b4ad09SPeter Avalos file_to_archive(cpio, p); 6019c82a63eSPeter Avalos lafe_line_reader_free(lr); 60260b4ad09SPeter Avalos 60360b4ad09SPeter Avalos /* 60460b4ad09SPeter Avalos * The hardlink detection may have queued up a couple of entries 60560b4ad09SPeter Avalos * that can now be flushed. 60660b4ad09SPeter Avalos */ 60760b4ad09SPeter Avalos entry = NULL; 60860b4ad09SPeter Avalos archive_entry_linkify(cpio->linkresolver, &entry, &spare); 60960b4ad09SPeter Avalos while (entry != NULL) { 61060b4ad09SPeter Avalos entry_to_archive(cpio, entry); 61160b4ad09SPeter Avalos archive_entry_free(entry); 61260b4ad09SPeter Avalos entry = NULL; 61360b4ad09SPeter Avalos archive_entry_linkify(cpio->linkresolver, &entry, &spare); 61460b4ad09SPeter Avalos } 61560b4ad09SPeter Avalos 61660b4ad09SPeter Avalos r = archive_write_close(cpio->archive); 617c09f92d2SPeter Avalos if (cpio->dot) 618c09f92d2SPeter Avalos fprintf(stderr, "\n"); 61960b4ad09SPeter Avalos if (r != ARCHIVE_OK) 6209c82a63eSPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); 62160b4ad09SPeter Avalos 62260b4ad09SPeter Avalos if (!cpio->quiet) { 6239c82a63eSPeter Avalos int64_t blocks = 624d4d8193eSPeter Avalos (archive_filter_bytes(cpio->archive, 0) + 511) 62560b4ad09SPeter Avalos / 512; 6269c82a63eSPeter Avalos fprintf(stderr, "%lu %s\n", (unsigned long)blocks, 62760b4ad09SPeter Avalos blocks == 1 ? "block" : "blocks"); 62860b4ad09SPeter Avalos } 629c09f92d2SPeter Avalos archive_write_free(cpio->archive); 63060b4ad09SPeter Avalos } 63160b4ad09SPeter Avalos 63259bf7050SPeter Avalos static const char * 63359bf7050SPeter Avalos remove_leading_slash(const char *p) 63459bf7050SPeter Avalos { 63559bf7050SPeter Avalos const char *rp; 63659bf7050SPeter Avalos 63759bf7050SPeter Avalos /* Remove leading "//./" or "//?/" or "//?/UNC/" 63859bf7050SPeter Avalos * (absolute path prefixes used by Windows API) */ 63959bf7050SPeter Avalos if ((p[0] == '/' || p[0] == '\\') && 64059bf7050SPeter Avalos (p[1] == '/' || p[1] == '\\') && 64159bf7050SPeter Avalos (p[2] == '.' || p[2] == '?') && 64259bf7050SPeter Avalos (p[3] == '/' || p[3] == '\\')) 64359bf7050SPeter Avalos { 64459bf7050SPeter Avalos if (p[2] == '?' && 64559bf7050SPeter Avalos (p[4] == 'U' || p[4] == 'u') && 64659bf7050SPeter Avalos (p[5] == 'N' || p[5] == 'n') && 64759bf7050SPeter Avalos (p[6] == 'C' || p[6] == 'c') && 64859bf7050SPeter Avalos (p[7] == '/' || p[7] == '\\')) 64959bf7050SPeter Avalos p += 8; 65059bf7050SPeter Avalos else 65159bf7050SPeter Avalos p += 4; 65259bf7050SPeter Avalos } 65359bf7050SPeter Avalos do { 65459bf7050SPeter Avalos rp = p; 65559bf7050SPeter Avalos /* Remove leading drive letter from archives created 65659bf7050SPeter Avalos * on Windows. */ 65759bf7050SPeter Avalos if (((p[0] >= 'a' && p[0] <= 'z') || 65859bf7050SPeter Avalos (p[0] >= 'A' && p[0] <= 'Z')) && 65959bf7050SPeter Avalos p[1] == ':') { 66059bf7050SPeter Avalos p += 2; 66159bf7050SPeter Avalos } 66259bf7050SPeter Avalos /* Remove leading "/../", "//", etc. */ 66359bf7050SPeter Avalos while (p[0] == '/' || p[0] == '\\') { 66459bf7050SPeter Avalos if (p[1] == '.' && p[2] == '.' && 66559bf7050SPeter Avalos (p[3] == '/' || p[3] == '\\')) { 66659bf7050SPeter Avalos p += 3; /* Remove "/..", leave "/" 66759bf7050SPeter Avalos * for next pass. */ 66859bf7050SPeter Avalos } else 66959bf7050SPeter Avalos p += 1; /* Remove "/". */ 67059bf7050SPeter Avalos } 67159bf7050SPeter Avalos } while (rp != p); 67259bf7050SPeter Avalos return (p); 67359bf7050SPeter Avalos } 67459bf7050SPeter Avalos 67560b4ad09SPeter Avalos /* 67660b4ad09SPeter Avalos * This is used by both out mode (to copy objects from disk into 67760b4ad09SPeter Avalos * an archive) and pass mode (to copy objects from disk to 67860b4ad09SPeter Avalos * an archive_write_disk "archive"). 67960b4ad09SPeter Avalos */ 68060b4ad09SPeter Avalos static int 68160b4ad09SPeter Avalos file_to_archive(struct cpio *cpio, const char *srcpath) 68260b4ad09SPeter Avalos { 68360b4ad09SPeter Avalos const char *destpath; 68460b4ad09SPeter Avalos struct archive_entry *entry, *spare; 68560b4ad09SPeter Avalos size_t len; 68660b4ad09SPeter Avalos int r; 68760b4ad09SPeter Avalos 68860b4ad09SPeter Avalos /* 68960b4ad09SPeter Avalos * Create an archive_entry describing the source file. 6908029ab02SPeter Avalos * 69160b4ad09SPeter Avalos */ 69260b4ad09SPeter Avalos entry = archive_entry_new(); 69360b4ad09SPeter Avalos if (entry == NULL) 6949c82a63eSPeter Avalos lafe_errc(1, 0, "Couldn't allocate entry"); 69560b4ad09SPeter Avalos archive_entry_copy_sourcepath(entry, srcpath); 6969c82a63eSPeter Avalos r = archive_read_disk_entry_from_file(cpio->archive_read_disk, 6979c82a63eSPeter Avalos entry, -1, NULL); 6989c82a63eSPeter Avalos if (r < ARCHIVE_FAILED) 6999c82a63eSPeter Avalos lafe_errc(1, 0, "%s", 7009c82a63eSPeter Avalos archive_error_string(cpio->archive_read_disk)); 7019c82a63eSPeter Avalos if (r < ARCHIVE_OK) 7029c82a63eSPeter Avalos lafe_warnc(0, "%s", 7039c82a63eSPeter Avalos archive_error_string(cpio->archive_read_disk)); 7049c82a63eSPeter Avalos if (r <= ARCHIVE_FAILED) { 7059c82a63eSPeter Avalos cpio->return_value = 1; 7069c82a63eSPeter Avalos return (r); 70760b4ad09SPeter Avalos } 70860b4ad09SPeter Avalos 709c09f92d2SPeter Avalos if (cpio->uid_override >= 0) { 7109c82a63eSPeter Avalos archive_entry_set_uid(entry, cpio->uid_override); 711c09f92d2SPeter Avalos archive_entry_set_uname(entry, cpio->uname_override); 712c09f92d2SPeter Avalos } 713c09f92d2SPeter Avalos if (cpio->gid_override >= 0) { 7149c82a63eSPeter Avalos archive_entry_set_gid(entry, cpio->gid_override); 715c09f92d2SPeter Avalos archive_entry_set_gname(entry, cpio->gname_override); 716c09f92d2SPeter Avalos } 71760b4ad09SPeter Avalos 71860b4ad09SPeter Avalos /* 71960b4ad09SPeter Avalos * Generate a destination path for this entry. 72060b4ad09SPeter Avalos * "destination path" is the name to which it will be copied in 72160b4ad09SPeter Avalos * pass mode or the name that will go into the archive in 72260b4ad09SPeter Avalos * output mode. 72360b4ad09SPeter Avalos */ 72460b4ad09SPeter Avalos destpath = srcpath; 72560b4ad09SPeter Avalos if (cpio->destdir) { 72660b4ad09SPeter Avalos len = strlen(cpio->destdir) + strlen(srcpath) + 8; 72760b4ad09SPeter Avalos if (len >= cpio->pass_destpath_alloc) { 72860b4ad09SPeter Avalos while (len >= cpio->pass_destpath_alloc) { 72960b4ad09SPeter Avalos cpio->pass_destpath_alloc += 512; 73060b4ad09SPeter Avalos cpio->pass_destpath_alloc *= 2; 73160b4ad09SPeter Avalos } 73260b4ad09SPeter Avalos free(cpio->pass_destpath); 73360b4ad09SPeter Avalos cpio->pass_destpath = malloc(cpio->pass_destpath_alloc); 73460b4ad09SPeter Avalos if (cpio->pass_destpath == NULL) 7359c82a63eSPeter Avalos lafe_errc(1, ENOMEM, 73660b4ad09SPeter Avalos "Can't allocate path buffer"); 73760b4ad09SPeter Avalos } 73860b4ad09SPeter Avalos strcpy(cpio->pass_destpath, cpio->destdir); 73959bf7050SPeter Avalos strcat(cpio->pass_destpath, remove_leading_slash(srcpath)); 74060b4ad09SPeter Avalos destpath = cpio->pass_destpath; 74160b4ad09SPeter Avalos } 74260b4ad09SPeter Avalos if (cpio->option_rename) 74360b4ad09SPeter Avalos destpath = cpio_rename(destpath); 74460b4ad09SPeter Avalos if (destpath == NULL) 74560b4ad09SPeter Avalos return (0); 74660b4ad09SPeter Avalos archive_entry_copy_pathname(entry, destpath); 74760b4ad09SPeter Avalos 74860b4ad09SPeter Avalos /* 74960b4ad09SPeter Avalos * If we're trying to preserve hardlinks, match them here. 75060b4ad09SPeter Avalos */ 75160b4ad09SPeter Avalos spare = NULL; 75260b4ad09SPeter Avalos if (cpio->linkresolver != NULL 7539c82a63eSPeter Avalos && archive_entry_filetype(entry) != AE_IFDIR) { 75460b4ad09SPeter Avalos archive_entry_linkify(cpio->linkresolver, &entry, &spare); 75560b4ad09SPeter Avalos } 75660b4ad09SPeter Avalos 75760b4ad09SPeter Avalos if (entry != NULL) { 75860b4ad09SPeter Avalos r = entry_to_archive(cpio, entry); 75960b4ad09SPeter Avalos archive_entry_free(entry); 76060b4ad09SPeter Avalos if (spare != NULL) { 76160b4ad09SPeter Avalos if (r == 0) 76260b4ad09SPeter Avalos r = entry_to_archive(cpio, spare); 76360b4ad09SPeter Avalos archive_entry_free(spare); 76460b4ad09SPeter Avalos } 7659c82a63eSPeter Avalos } 76660b4ad09SPeter Avalos return (r); 76760b4ad09SPeter Avalos } 76860b4ad09SPeter Avalos 76960b4ad09SPeter Avalos static int 77060b4ad09SPeter Avalos entry_to_archive(struct cpio *cpio, struct archive_entry *entry) 77160b4ad09SPeter Avalos { 77260b4ad09SPeter Avalos const char *destpath = archive_entry_pathname(entry); 77360b4ad09SPeter Avalos const char *srcpath = archive_entry_sourcepath(entry); 77460b4ad09SPeter Avalos int fd = -1; 77560b4ad09SPeter Avalos ssize_t bytes_read; 77660b4ad09SPeter Avalos int r; 77760b4ad09SPeter Avalos 77860b4ad09SPeter Avalos /* Print out the destination name to the user. */ 77960b4ad09SPeter Avalos if (cpio->verbose) 78060b4ad09SPeter Avalos fprintf(stderr,"%s", destpath); 781c09f92d2SPeter Avalos if (cpio->dot) 782c09f92d2SPeter Avalos fprintf(stderr, "."); 78360b4ad09SPeter Avalos 78460b4ad09SPeter Avalos /* 78560b4ad09SPeter Avalos * Option_link only makes sense in pass mode and for 78660b4ad09SPeter Avalos * regular files. Also note: if a link operation fails 78760b4ad09SPeter Avalos * because of cross-device restrictions, we'll fall back 78860b4ad09SPeter Avalos * to copy mode for that entry. 78960b4ad09SPeter Avalos * 79060b4ad09SPeter Avalos * TODO: Test other cpio implementations to see if they 79160b4ad09SPeter Avalos * hard-link anything other than regular files here. 79260b4ad09SPeter Avalos */ 79360b4ad09SPeter Avalos if (cpio->option_link 79460b4ad09SPeter Avalos && archive_entry_filetype(entry) == AE_IFREG) 79560b4ad09SPeter Avalos { 79660b4ad09SPeter Avalos struct archive_entry *t; 79760b4ad09SPeter Avalos /* Save the original entry in case we need it later. */ 79860b4ad09SPeter Avalos t = archive_entry_clone(entry); 79960b4ad09SPeter Avalos if (t == NULL) 8009c82a63eSPeter Avalos lafe_errc(1, ENOMEM, "Can't create link"); 80160b4ad09SPeter Avalos /* Note: link(2) doesn't create parent directories, 80260b4ad09SPeter Avalos * so we use archive_write_header() instead as a 80360b4ad09SPeter Avalos * convenience. */ 80460b4ad09SPeter Avalos archive_entry_set_hardlink(t, srcpath); 80560b4ad09SPeter Avalos /* This is a straight link that carries no data. */ 80660b4ad09SPeter Avalos archive_entry_set_size(t, 0); 80760b4ad09SPeter Avalos r = archive_write_header(cpio->archive, t); 80860b4ad09SPeter Avalos archive_entry_free(t); 80960b4ad09SPeter Avalos if (r != ARCHIVE_OK) 8109c82a63eSPeter Avalos lafe_warnc(archive_errno(cpio->archive), 8119c82a63eSPeter Avalos "%s", archive_error_string(cpio->archive)); 81260b4ad09SPeter Avalos if (r == ARCHIVE_FATAL) 81360b4ad09SPeter Avalos exit(1); 81460b4ad09SPeter Avalos #ifdef EXDEV 81560b4ad09SPeter Avalos if (r != ARCHIVE_OK && archive_errno(cpio->archive) == EXDEV) { 81660b4ad09SPeter Avalos /* Cross-device link: Just fall through and use 81760b4ad09SPeter Avalos * the original entry to copy the file over. */ 8189c82a63eSPeter Avalos lafe_warnc(0, "Copying file instead"); 81960b4ad09SPeter Avalos } else 82060b4ad09SPeter Avalos #endif 82160b4ad09SPeter Avalos return (0); 82260b4ad09SPeter Avalos } 82360b4ad09SPeter Avalos 82460b4ad09SPeter Avalos /* 82560b4ad09SPeter Avalos * Make sure we can open the file (if necessary) before 82660b4ad09SPeter Avalos * trying to write the header. 82760b4ad09SPeter Avalos */ 82860b4ad09SPeter Avalos if (archive_entry_filetype(entry) == AE_IFREG) { 82960b4ad09SPeter Avalos if (archive_entry_size(entry) > 0) { 8309c82a63eSPeter Avalos fd = open(srcpath, O_RDONLY | O_BINARY); 83160b4ad09SPeter Avalos if (fd < 0) { 8329c82a63eSPeter Avalos lafe_warnc(errno, 83360b4ad09SPeter Avalos "%s: could not open file", srcpath); 83460b4ad09SPeter Avalos goto cleanup; 83560b4ad09SPeter Avalos } 83660b4ad09SPeter Avalos } 83760b4ad09SPeter Avalos } else { 83860b4ad09SPeter Avalos archive_entry_set_size(entry, 0); 83960b4ad09SPeter Avalos } 84060b4ad09SPeter Avalos 84160b4ad09SPeter Avalos r = archive_write_header(cpio->archive, entry); 84260b4ad09SPeter Avalos 84360b4ad09SPeter Avalos if (r != ARCHIVE_OK) 8449c82a63eSPeter Avalos lafe_warnc(archive_errno(cpio->archive), 84560b4ad09SPeter Avalos "%s: %s", 8468029ab02SPeter Avalos srcpath, 84760b4ad09SPeter Avalos archive_error_string(cpio->archive)); 84860b4ad09SPeter Avalos 84960b4ad09SPeter Avalos if (r == ARCHIVE_FATAL) 85060b4ad09SPeter Avalos exit(1); 85160b4ad09SPeter Avalos 852c09f92d2SPeter Avalos if (r >= ARCHIVE_WARN && archive_entry_size(entry) > 0 && fd >= 0) { 853d4d8193eSPeter Avalos bytes_read = read(fd, cpio->buff, (unsigned)cpio->buff_size); 85460b4ad09SPeter Avalos while (bytes_read > 0) { 855d4d8193eSPeter Avalos ssize_t bytes_write; 856d4d8193eSPeter Avalos bytes_write = archive_write_data(cpio->archive, 85760b4ad09SPeter Avalos cpio->buff, bytes_read); 858d4d8193eSPeter Avalos if (bytes_write < 0) 8599c82a63eSPeter Avalos lafe_errc(1, archive_errno(cpio->archive), 8609c82a63eSPeter Avalos "%s", archive_error_string(cpio->archive)); 861d4d8193eSPeter Avalos if (bytes_write < bytes_read) { 8629c82a63eSPeter Avalos lafe_warnc(0, 863d4d8193eSPeter Avalos "Truncated write; file may have " 864d4d8193eSPeter Avalos "grown while being archived."); 86560b4ad09SPeter Avalos } 866d4d8193eSPeter Avalos bytes_read = read(fd, cpio->buff, 867d4d8193eSPeter Avalos (unsigned)cpio->buff_size); 86860b4ad09SPeter Avalos } 86960b4ad09SPeter Avalos } 87060b4ad09SPeter Avalos 8718029ab02SPeter Avalos fd = restore_time(cpio, entry, srcpath, fd); 87260b4ad09SPeter Avalos 87360b4ad09SPeter Avalos cleanup: 87460b4ad09SPeter Avalos if (cpio->verbose) 87560b4ad09SPeter Avalos fprintf(stderr,"\n"); 87660b4ad09SPeter Avalos if (fd >= 0) 87760b4ad09SPeter Avalos close(fd); 87860b4ad09SPeter Avalos return (0); 87960b4ad09SPeter Avalos } 88060b4ad09SPeter Avalos 8818029ab02SPeter Avalos static int 88260b4ad09SPeter Avalos restore_time(struct cpio *cpio, struct archive_entry *entry, 88360b4ad09SPeter Avalos const char *name, int fd) 88460b4ad09SPeter Avalos { 88560b4ad09SPeter Avalos #ifndef HAVE_UTIMES 88660b4ad09SPeter Avalos static int warned = 0; 88760b4ad09SPeter Avalos 88860b4ad09SPeter Avalos (void)cpio; /* UNUSED */ 88960b4ad09SPeter Avalos (void)entry; /* UNUSED */ 89060b4ad09SPeter Avalos (void)name; /* UNUSED */ 89160b4ad09SPeter Avalos 89260b4ad09SPeter Avalos if (!warned) 8939c82a63eSPeter Avalos lafe_warnc(0, "Can't restore access times on this platform"); 89460b4ad09SPeter Avalos warned = 1; 8958029ab02SPeter Avalos return (fd); 8968029ab02SPeter Avalos #else 8978029ab02SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 8988029ab02SPeter Avalos struct __timeval times[2]; 89960b4ad09SPeter Avalos #else 90060b4ad09SPeter Avalos struct timeval times[2]; 9018029ab02SPeter Avalos #endif 90260b4ad09SPeter Avalos 90360b4ad09SPeter Avalos if (!cpio->option_atime_restore) 9048029ab02SPeter Avalos return (fd); 90560b4ad09SPeter Avalos 90660b4ad09SPeter Avalos times[1].tv_sec = archive_entry_mtime(entry); 90760b4ad09SPeter Avalos times[1].tv_usec = archive_entry_mtime_nsec(entry) / 1000; 90860b4ad09SPeter Avalos 90960b4ad09SPeter Avalos times[0].tv_sec = archive_entry_atime(entry); 91060b4ad09SPeter Avalos times[0].tv_usec = archive_entry_atime_nsec(entry) / 1000; 91160b4ad09SPeter Avalos 9129c82a63eSPeter Avalos #if defined(HAVE_FUTIMES) && !defined(__CYGWIN__) 91360b4ad09SPeter Avalos if (fd >= 0 && futimes(fd, times) == 0) 9148029ab02SPeter Avalos return (fd); 91560b4ad09SPeter Avalos #endif 9168029ab02SPeter Avalos /* 9178029ab02SPeter Avalos * Some platform cannot restore access times if the file descriptor 9188029ab02SPeter Avalos * is still opened. 9198029ab02SPeter Avalos */ 9208029ab02SPeter Avalos if (fd >= 0) { 9218029ab02SPeter Avalos close(fd); 9228029ab02SPeter Avalos fd = -1; 9238029ab02SPeter Avalos } 92460b4ad09SPeter Avalos 92560b4ad09SPeter Avalos #ifdef HAVE_LUTIMES 92660b4ad09SPeter Avalos if (lutimes(name, times) != 0) 92760b4ad09SPeter Avalos #else 9289c82a63eSPeter Avalos if ((AE_IFLNK != archive_entry_filetype(entry)) 9299c82a63eSPeter Avalos && utimes(name, times) != 0) 93060b4ad09SPeter Avalos #endif 9319c82a63eSPeter Avalos lafe_warnc(errno, "Can't update time for %s", name); 93260b4ad09SPeter Avalos #endif 9338029ab02SPeter Avalos return (fd); 93460b4ad09SPeter Avalos } 93560b4ad09SPeter Avalos 93660b4ad09SPeter Avalos 93760b4ad09SPeter Avalos static void 93860b4ad09SPeter Avalos mode_in(struct cpio *cpio) 93960b4ad09SPeter Avalos { 94060b4ad09SPeter Avalos struct archive *a; 94160b4ad09SPeter Avalos struct archive_entry *entry; 94260b4ad09SPeter Avalos struct archive *ext; 94360b4ad09SPeter Avalos const char *destpath; 94460b4ad09SPeter Avalos int r; 94560b4ad09SPeter Avalos 94660b4ad09SPeter Avalos ext = archive_write_disk_new(); 94760b4ad09SPeter Avalos if (ext == NULL) 9489c82a63eSPeter Avalos lafe_errc(1, 0, "Couldn't allocate restore object"); 94960b4ad09SPeter Avalos r = archive_write_disk_set_options(ext, cpio->extract_flags); 95060b4ad09SPeter Avalos if (r != ARCHIVE_OK) 9519c82a63eSPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(ext)); 95260b4ad09SPeter Avalos a = archive_read_new(); 95360b4ad09SPeter Avalos if (a == NULL) 9549c82a63eSPeter Avalos lafe_errc(1, 0, "Couldn't allocate archive object"); 955c09f92d2SPeter Avalos archive_read_support_filter_all(a); 95660b4ad09SPeter Avalos archive_read_support_format_all(a); 957*6b384f39SPeter Avalos if (cpio->passphrase != NULL) 958*6b384f39SPeter Avalos r = archive_read_add_passphrase(a, cpio->passphrase); 959*6b384f39SPeter Avalos else 960*6b384f39SPeter Avalos r = archive_read_set_passphrase_callback(a, cpio, 961*6b384f39SPeter Avalos &passphrase_callback); 962*6b384f39SPeter Avalos if (r != ARCHIVE_OK) 963*6b384f39SPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(a)); 96460b4ad09SPeter Avalos 965d4d8193eSPeter Avalos if (archive_read_open_filename(a, cpio->filename, 966d4d8193eSPeter Avalos cpio->bytes_per_block)) 9679c82a63eSPeter Avalos lafe_errc(1, archive_errno(a), 9689c82a63eSPeter Avalos "%s", archive_error_string(a)); 96960b4ad09SPeter Avalos for (;;) { 97060b4ad09SPeter Avalos r = archive_read_next_header(a, &entry); 97160b4ad09SPeter Avalos if (r == ARCHIVE_EOF) 97260b4ad09SPeter Avalos break; 97360b4ad09SPeter Avalos if (r != ARCHIVE_OK) { 9749c82a63eSPeter Avalos lafe_errc(1, archive_errno(a), 9759c82a63eSPeter Avalos "%s", archive_error_string(a)); 97660b4ad09SPeter Avalos } 97759bf7050SPeter Avalos if (archive_match_path_excluded(cpio->matching, entry)) 97860b4ad09SPeter Avalos continue; 97960b4ad09SPeter Avalos if (cpio->option_rename) { 98060b4ad09SPeter Avalos destpath = cpio_rename(archive_entry_pathname(entry)); 98160b4ad09SPeter Avalos archive_entry_set_pathname(entry, destpath); 98260b4ad09SPeter Avalos } else 98360b4ad09SPeter Avalos destpath = archive_entry_pathname(entry); 98460b4ad09SPeter Avalos if (destpath == NULL) 98560b4ad09SPeter Avalos continue; 98660b4ad09SPeter Avalos if (cpio->verbose) 987c09f92d2SPeter Avalos fprintf(stderr, "%s\n", destpath); 988c09f92d2SPeter Avalos if (cpio->dot) 989c09f92d2SPeter Avalos fprintf(stderr, "."); 99060b4ad09SPeter Avalos if (cpio->uid_override >= 0) 99160b4ad09SPeter Avalos archive_entry_set_uid(entry, cpio->uid_override); 99260b4ad09SPeter Avalos if (cpio->gid_override >= 0) 99360b4ad09SPeter Avalos archive_entry_set_gid(entry, cpio->gid_override); 99460b4ad09SPeter Avalos r = archive_write_header(ext, entry); 99560b4ad09SPeter Avalos if (r != ARCHIVE_OK) { 99660b4ad09SPeter Avalos fprintf(stderr, "%s: %s\n", 99760b4ad09SPeter Avalos archive_entry_pathname(entry), 99860b4ad09SPeter Avalos archive_error_string(ext)); 99955c601bbSPeter Avalos } else if (!archive_entry_size_is_set(entry) 100055c601bbSPeter Avalos || archive_entry_size(entry) > 0) { 10019c82a63eSPeter Avalos r = extract_data(a, ext); 10029c82a63eSPeter Avalos if (r != ARCHIVE_OK) 10039c82a63eSPeter Avalos cpio->return_value = 1; 100460b4ad09SPeter Avalos } 100560b4ad09SPeter Avalos } 100660b4ad09SPeter Avalos r = archive_read_close(a); 1007c09f92d2SPeter Avalos if (cpio->dot) 1008c09f92d2SPeter Avalos fprintf(stderr, "\n"); 100960b4ad09SPeter Avalos if (r != ARCHIVE_OK) 10109c82a63eSPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(a)); 101160b4ad09SPeter Avalos r = archive_write_close(ext); 101260b4ad09SPeter Avalos if (r != ARCHIVE_OK) 10139c82a63eSPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(ext)); 101460b4ad09SPeter Avalos if (!cpio->quiet) { 1015d4d8193eSPeter Avalos int64_t blocks = (archive_filter_bytes(a, 0) + 511) 101660b4ad09SPeter Avalos / 512; 10179c82a63eSPeter Avalos fprintf(stderr, "%lu %s\n", (unsigned long)blocks, 101860b4ad09SPeter Avalos blocks == 1 ? "block" : "blocks"); 101960b4ad09SPeter Avalos } 1020c09f92d2SPeter Avalos archive_read_free(a); 1021c09f92d2SPeter Avalos archive_write_free(ext); 10229c82a63eSPeter Avalos exit(cpio->return_value); 102360b4ad09SPeter Avalos } 102460b4ad09SPeter Avalos 10259c82a63eSPeter Avalos /* 10269c82a63eSPeter Avalos * Exits if there's a fatal error. Returns ARCHIVE_OK 10279c82a63eSPeter Avalos * if everything is kosher. 10289c82a63eSPeter Avalos */ 102960b4ad09SPeter Avalos static int 10309c82a63eSPeter Avalos extract_data(struct archive *ar, struct archive *aw) 103160b4ad09SPeter Avalos { 103260b4ad09SPeter Avalos int r; 103360b4ad09SPeter Avalos size_t size; 103460b4ad09SPeter Avalos const void *block; 1035c09f92d2SPeter Avalos int64_t offset; 103660b4ad09SPeter Avalos 103760b4ad09SPeter Avalos for (;;) { 103860b4ad09SPeter Avalos r = archive_read_data_block(ar, &block, &size, &offset); 103960b4ad09SPeter Avalos if (r == ARCHIVE_EOF) 104060b4ad09SPeter Avalos return (ARCHIVE_OK); 104160b4ad09SPeter Avalos if (r != ARCHIVE_OK) { 10429c82a63eSPeter Avalos lafe_warnc(archive_errno(ar), 104360b4ad09SPeter Avalos "%s", archive_error_string(ar)); 10449c82a63eSPeter Avalos exit(1); 104560b4ad09SPeter Avalos } 1046d4d8193eSPeter Avalos r = (int)archive_write_data_block(aw, block, size, offset); 104760b4ad09SPeter Avalos if (r != ARCHIVE_OK) { 10489c82a63eSPeter Avalos lafe_warnc(archive_errno(aw), 10499c82a63eSPeter Avalos "%s", archive_error_string(aw)); 105060b4ad09SPeter Avalos return (r); 105160b4ad09SPeter Avalos } 105260b4ad09SPeter Avalos } 105360b4ad09SPeter Avalos } 105460b4ad09SPeter Avalos 105560b4ad09SPeter Avalos static void 105660b4ad09SPeter Avalos mode_list(struct cpio *cpio) 105760b4ad09SPeter Avalos { 105860b4ad09SPeter Avalos struct archive *a; 105960b4ad09SPeter Avalos struct archive_entry *entry; 106060b4ad09SPeter Avalos int r; 106160b4ad09SPeter Avalos 106260b4ad09SPeter Avalos a = archive_read_new(); 106360b4ad09SPeter Avalos if (a == NULL) 10649c82a63eSPeter Avalos lafe_errc(1, 0, "Couldn't allocate archive object"); 1065c09f92d2SPeter Avalos archive_read_support_filter_all(a); 106660b4ad09SPeter Avalos archive_read_support_format_all(a); 1067*6b384f39SPeter Avalos if (cpio->passphrase != NULL) 1068*6b384f39SPeter Avalos r = archive_read_add_passphrase(a, cpio->passphrase); 1069*6b384f39SPeter Avalos else 1070*6b384f39SPeter Avalos r = archive_read_set_passphrase_callback(a, cpio, 1071*6b384f39SPeter Avalos &passphrase_callback); 1072*6b384f39SPeter Avalos if (r != ARCHIVE_OK) 1073*6b384f39SPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(a)); 107460b4ad09SPeter Avalos 1075d4d8193eSPeter Avalos if (archive_read_open_filename(a, cpio->filename, 1076d4d8193eSPeter Avalos cpio->bytes_per_block)) 10779c82a63eSPeter Avalos lafe_errc(1, archive_errno(a), 10789c82a63eSPeter Avalos "%s", archive_error_string(a)); 107960b4ad09SPeter Avalos for (;;) { 108060b4ad09SPeter Avalos r = archive_read_next_header(a, &entry); 108160b4ad09SPeter Avalos if (r == ARCHIVE_EOF) 108260b4ad09SPeter Avalos break; 108360b4ad09SPeter Avalos if (r != ARCHIVE_OK) { 10849c82a63eSPeter Avalos lafe_errc(1, archive_errno(a), 10859c82a63eSPeter Avalos "%s", archive_error_string(a)); 108660b4ad09SPeter Avalos } 108759bf7050SPeter Avalos if (archive_match_path_excluded(cpio->matching, entry)) 108860b4ad09SPeter Avalos continue; 10898029ab02SPeter Avalos if (cpio->verbose) 10908029ab02SPeter Avalos list_item_verbose(cpio, entry); 10918029ab02SPeter Avalos else 109260b4ad09SPeter Avalos fprintf(stdout, "%s\n", archive_entry_pathname(entry)); 109360b4ad09SPeter Avalos } 109460b4ad09SPeter Avalos r = archive_read_close(a); 109560b4ad09SPeter Avalos if (r != ARCHIVE_OK) 10969c82a63eSPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(a)); 109760b4ad09SPeter Avalos if (!cpio->quiet) { 1098d4d8193eSPeter Avalos int64_t blocks = (archive_filter_bytes(a, 0) + 511) 109960b4ad09SPeter Avalos / 512; 11009c82a63eSPeter Avalos fprintf(stderr, "%lu %s\n", (unsigned long)blocks, 110160b4ad09SPeter Avalos blocks == 1 ? "block" : "blocks"); 110260b4ad09SPeter Avalos } 1103c09f92d2SPeter Avalos archive_read_free(a); 110460b4ad09SPeter Avalos exit(0); 110560b4ad09SPeter Avalos } 110660b4ad09SPeter Avalos 11078029ab02SPeter Avalos /* 11088029ab02SPeter Avalos * Display information about the current file. 11098029ab02SPeter Avalos * 11108029ab02SPeter Avalos * The format here roughly duplicates the output of 'ls -l'. 11118029ab02SPeter Avalos * This is based on SUSv2, where 'tar tv' is documented as 11128029ab02SPeter Avalos * listing additional information in an "unspecified format," 11138029ab02SPeter Avalos * and 'pax -l' is documented as using the same format as 'ls -l'. 11148029ab02SPeter Avalos */ 11158029ab02SPeter Avalos static void 11168029ab02SPeter Avalos list_item_verbose(struct cpio *cpio, struct archive_entry *entry) 11178029ab02SPeter Avalos { 11188029ab02SPeter Avalos char size[32]; 11198029ab02SPeter Avalos char date[32]; 11208029ab02SPeter Avalos char uids[16], gids[16]; 11218029ab02SPeter Avalos const char *uname, *gname; 11228029ab02SPeter Avalos FILE *out = stdout; 11238029ab02SPeter Avalos const char *fmt; 11249c82a63eSPeter Avalos time_t mtime; 11258029ab02SPeter Avalos static time_t now; 11268029ab02SPeter Avalos 11278029ab02SPeter Avalos if (!now) 11288029ab02SPeter Avalos time(&now); 11298029ab02SPeter Avalos 11308029ab02SPeter Avalos if (cpio->option_numeric_uid_gid) { 11318029ab02SPeter Avalos /* Format numeric uid/gid for display. */ 11329c82a63eSPeter Avalos strcpy(uids, cpio_i64toa(archive_entry_uid(entry))); 11338029ab02SPeter Avalos uname = uids; 11349c82a63eSPeter Avalos strcpy(gids, cpio_i64toa(archive_entry_gid(entry))); 11358029ab02SPeter Avalos gname = gids; 11368029ab02SPeter Avalos } else { 11378029ab02SPeter Avalos /* Use uname if it's present, else lookup name from uid. */ 11388029ab02SPeter Avalos uname = archive_entry_uname(entry); 11398029ab02SPeter Avalos if (uname == NULL) 1140c09f92d2SPeter Avalos uname = lookup_uname(cpio, (uid_t)archive_entry_uid(entry)); 11418029ab02SPeter Avalos /* Use gname if it's present, else lookup name from gid. */ 11428029ab02SPeter Avalos gname = archive_entry_gname(entry); 11438029ab02SPeter Avalos if (gname == NULL) 1144c09f92d2SPeter Avalos gname = lookup_gname(cpio, (uid_t)archive_entry_gid(entry)); 11458029ab02SPeter Avalos } 11468029ab02SPeter Avalos 11478029ab02SPeter Avalos /* Print device number or file size. */ 11489c82a63eSPeter Avalos if (archive_entry_filetype(entry) == AE_IFCHR 11499c82a63eSPeter Avalos || archive_entry_filetype(entry) == AE_IFBLK) { 11508029ab02SPeter Avalos snprintf(size, sizeof(size), "%lu,%lu", 11519c82a63eSPeter Avalos (unsigned long)archive_entry_rdevmajor(entry), 11529c82a63eSPeter Avalos (unsigned long)archive_entry_rdevminor(entry)); 11538029ab02SPeter Avalos } else { 11549c82a63eSPeter Avalos strcpy(size, cpio_i64toa(archive_entry_size(entry))); 11558029ab02SPeter Avalos } 11568029ab02SPeter Avalos 11578029ab02SPeter Avalos /* Format the time using 'ls -l' conventions. */ 11589c82a63eSPeter Avalos mtime = archive_entry_mtime(entry); 11598029ab02SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 11608029ab02SPeter Avalos /* Windows' strftime function does not support %e format. */ 11619c82a63eSPeter Avalos if (mtime - now > 365*86400/2 11629c82a63eSPeter Avalos || mtime - now < -365*86400/2) 11638029ab02SPeter Avalos fmt = cpio->day_first ? "%d %b %Y" : "%b %d %Y"; 11648029ab02SPeter Avalos else 11658029ab02SPeter Avalos fmt = cpio->day_first ? "%d %b %H:%M" : "%b %d %H:%M"; 11668029ab02SPeter Avalos #else 1167*6b384f39SPeter Avalos if (mtime - now > 365*86400/2 1168*6b384f39SPeter Avalos || mtime - now < -365*86400/2) 11698029ab02SPeter Avalos fmt = cpio->day_first ? "%e %b %Y" : "%b %e %Y"; 11708029ab02SPeter Avalos else 11718029ab02SPeter Avalos fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M"; 11728029ab02SPeter Avalos #endif 11739c82a63eSPeter Avalos strftime(date, sizeof(date), fmt, localtime(&mtime)); 11748029ab02SPeter Avalos 11758029ab02SPeter Avalos fprintf(out, "%s%3d %-8s %-8s %8s %12s %s", 11768029ab02SPeter Avalos archive_entry_strmode(entry), 11778029ab02SPeter Avalos archive_entry_nlink(entry), 11788029ab02SPeter Avalos uname, gname, size, date, 11798029ab02SPeter Avalos archive_entry_pathname(entry)); 11808029ab02SPeter Avalos 11818029ab02SPeter Avalos /* Extra information for links. */ 11828029ab02SPeter Avalos if (archive_entry_hardlink(entry)) /* Hard link */ 11838029ab02SPeter Avalos fprintf(out, " link to %s", archive_entry_hardlink(entry)); 11848029ab02SPeter Avalos else if (archive_entry_symlink(entry)) /* Symbolic link */ 11858029ab02SPeter Avalos fprintf(out, " -> %s", archive_entry_symlink(entry)); 11868029ab02SPeter Avalos fprintf(out, "\n"); 11878029ab02SPeter Avalos } 11888029ab02SPeter Avalos 118960b4ad09SPeter Avalos static void 119060b4ad09SPeter Avalos mode_pass(struct cpio *cpio, const char *destdir) 119160b4ad09SPeter Avalos { 11929c82a63eSPeter Avalos struct lafe_line_reader *lr; 119360b4ad09SPeter Avalos const char *p; 119460b4ad09SPeter Avalos int r; 119560b4ad09SPeter Avalos 119660b4ad09SPeter Avalos /* Ensure target dir has a trailing '/' to simplify path surgery. */ 119760b4ad09SPeter Avalos cpio->destdir = malloc(strlen(destdir) + 8); 119860b4ad09SPeter Avalos strcpy(cpio->destdir, destdir); 119960b4ad09SPeter Avalos if (destdir[strlen(destdir) - 1] != '/') 120060b4ad09SPeter Avalos strcat(cpio->destdir, "/"); 120160b4ad09SPeter Avalos 120260b4ad09SPeter Avalos cpio->archive = archive_write_disk_new(); 120360b4ad09SPeter Avalos if (cpio->archive == NULL) 12049c82a63eSPeter Avalos lafe_errc(1, 0, "Failed to allocate archive object"); 120560b4ad09SPeter Avalos r = archive_write_disk_set_options(cpio->archive, cpio->extract_flags); 120660b4ad09SPeter Avalos if (r != ARCHIVE_OK) 12079c82a63eSPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); 120860b4ad09SPeter Avalos cpio->linkresolver = archive_entry_linkresolver_new(); 120960b4ad09SPeter Avalos archive_write_disk_set_standard_lookup(cpio->archive); 12109c82a63eSPeter Avalos 12119c82a63eSPeter Avalos cpio->archive_read_disk = archive_read_disk_new(); 12129c82a63eSPeter Avalos if (cpio->archive_read_disk == NULL) 12139c82a63eSPeter Avalos lafe_errc(1, 0, "Failed to allocate archive object"); 12149c82a63eSPeter Avalos if (cpio->option_follow_links) 12159c82a63eSPeter Avalos archive_read_disk_set_symlink_logical(cpio->archive_read_disk); 12169c82a63eSPeter Avalos else 12179c82a63eSPeter Avalos archive_read_disk_set_symlink_physical(cpio->archive_read_disk); 12189c82a63eSPeter Avalos archive_read_disk_set_standard_lookup(cpio->archive_read_disk); 12199c82a63eSPeter Avalos 12209c82a63eSPeter Avalos lr = lafe_line_reader("-", cpio->option_null); 12219c82a63eSPeter Avalos while ((p = lafe_line_reader_next(lr)) != NULL) 122260b4ad09SPeter Avalos file_to_archive(cpio, p); 12239c82a63eSPeter Avalos lafe_line_reader_free(lr); 122460b4ad09SPeter Avalos 122560b4ad09SPeter Avalos archive_entry_linkresolver_free(cpio->linkresolver); 122660b4ad09SPeter Avalos r = archive_write_close(cpio->archive); 1227c09f92d2SPeter Avalos if (cpio->dot) 1228c09f92d2SPeter Avalos fprintf(stderr, "\n"); 122960b4ad09SPeter Avalos if (r != ARCHIVE_OK) 12309c82a63eSPeter Avalos lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); 12318029ab02SPeter Avalos 12328029ab02SPeter Avalos if (!cpio->quiet) { 12339c82a63eSPeter Avalos int64_t blocks = 1234d4d8193eSPeter Avalos (archive_filter_bytes(cpio->archive, 0) + 511) 12358029ab02SPeter Avalos / 512; 12369c82a63eSPeter Avalos fprintf(stderr, "%lu %s\n", (unsigned long)blocks, 12378029ab02SPeter Avalos blocks == 1 ? "block" : "blocks"); 12388029ab02SPeter Avalos } 12398029ab02SPeter Avalos 1240c09f92d2SPeter Avalos archive_write_free(cpio->archive); 124160b4ad09SPeter Avalos } 124260b4ad09SPeter Avalos 124360b4ad09SPeter Avalos /* 124460b4ad09SPeter Avalos * Prompt for a new name for this entry. Returns a pointer to the 124560b4ad09SPeter Avalos * new name or NULL if the entry should not be copied. This 124660b4ad09SPeter Avalos * implements the semantics defined in POSIX.1-1996, which specifies 124760b4ad09SPeter Avalos * that an input of '.' means the name should be unchanged. GNU cpio 124860b4ad09SPeter Avalos * treats '.' as a literal new name. 124960b4ad09SPeter Avalos */ 125060b4ad09SPeter Avalos static const char * 125160b4ad09SPeter Avalos cpio_rename(const char *name) 125260b4ad09SPeter Avalos { 125360b4ad09SPeter Avalos static char buff[1024]; 125460b4ad09SPeter Avalos FILE *t; 125560b4ad09SPeter Avalos char *p, *ret; 125659bf7050SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 125759bf7050SPeter Avalos FILE *to; 125860b4ad09SPeter Avalos 125959bf7050SPeter Avalos t = fopen("CONIN$", "r"); 126059bf7050SPeter Avalos if (t == NULL) 126159bf7050SPeter Avalos return (name); 126259bf7050SPeter Avalos to = fopen("CONOUT$", "w"); 1263*6b384f39SPeter Avalos if (to == NULL) { 1264*6b384f39SPeter Avalos fclose(t); 126559bf7050SPeter Avalos return (name); 1266*6b384f39SPeter Avalos } 126759bf7050SPeter Avalos fprintf(to, "%s (Enter/./(new name))? ", name); 126859bf7050SPeter Avalos fclose(to); 126959bf7050SPeter Avalos #else 127060b4ad09SPeter Avalos t = fopen("/dev/tty", "r+"); 127160b4ad09SPeter Avalos if (t == NULL) 127260b4ad09SPeter Avalos return (name); 127360b4ad09SPeter Avalos fprintf(t, "%s (Enter/./(new name))? ", name); 127460b4ad09SPeter Avalos fflush(t); 127559bf7050SPeter Avalos #endif 127660b4ad09SPeter Avalos 127760b4ad09SPeter Avalos p = fgets(buff, sizeof(buff), t); 127860b4ad09SPeter Avalos fclose(t); 127960b4ad09SPeter Avalos if (p == NULL) 128060b4ad09SPeter Avalos /* End-of-file is a blank line. */ 128160b4ad09SPeter Avalos return (NULL); 128260b4ad09SPeter Avalos 128360b4ad09SPeter Avalos while (*p == ' ' || *p == '\t') 128460b4ad09SPeter Avalos ++p; 128560b4ad09SPeter Avalos if (*p == '\n' || *p == '\0') 128660b4ad09SPeter Avalos /* Empty line. */ 128760b4ad09SPeter Avalos return (NULL); 128860b4ad09SPeter Avalos if (*p == '.' && p[1] == '\n') 128960b4ad09SPeter Avalos /* Single period preserves original name. */ 129060b4ad09SPeter Avalos return (name); 129160b4ad09SPeter Avalos ret = p; 129260b4ad09SPeter Avalos /* Trim the final newline. */ 129360b4ad09SPeter Avalos while (*p != '\0' && *p != '\n') 129460b4ad09SPeter Avalos ++p; 129560b4ad09SPeter Avalos /* Overwrite the final \n with a null character. */ 129660b4ad09SPeter Avalos *p = '\0'; 129760b4ad09SPeter Avalos return (ret); 129860b4ad09SPeter Avalos } 129960b4ad09SPeter Avalos 13008029ab02SPeter Avalos static void 13018029ab02SPeter Avalos free_cache(struct name_cache *cache) 13028029ab02SPeter Avalos { 13038029ab02SPeter Avalos size_t i; 13048029ab02SPeter Avalos 13058029ab02SPeter Avalos if (cache != NULL) { 13068029ab02SPeter Avalos for (i = 0; i < cache->size; i++) 13078029ab02SPeter Avalos free(cache->cache[i].name); 13088029ab02SPeter Avalos free(cache); 13098029ab02SPeter Avalos } 13108029ab02SPeter Avalos } 13118029ab02SPeter Avalos 13128029ab02SPeter Avalos /* 13138029ab02SPeter Avalos * Lookup uname/gname from uid/gid, return NULL if no match. 13148029ab02SPeter Avalos */ 13158029ab02SPeter Avalos static const char * 13168029ab02SPeter Avalos lookup_name(struct cpio *cpio, struct name_cache **name_cache_variable, 13178029ab02SPeter Avalos int (*lookup_fn)(struct cpio *, const char **, id_t), id_t id) 13188029ab02SPeter Avalos { 13198029ab02SPeter Avalos char asnum[16]; 13208029ab02SPeter Avalos struct name_cache *cache; 13218029ab02SPeter Avalos const char *name; 13228029ab02SPeter Avalos int slot; 13238029ab02SPeter Avalos 13248029ab02SPeter Avalos 13258029ab02SPeter Avalos if (*name_cache_variable == NULL) { 13268029ab02SPeter Avalos *name_cache_variable = malloc(sizeof(struct name_cache)); 13278029ab02SPeter Avalos if (*name_cache_variable == NULL) 13289c82a63eSPeter Avalos lafe_errc(1, ENOMEM, "No more memory"); 13298029ab02SPeter Avalos memset(*name_cache_variable, 0, sizeof(struct name_cache)); 13308029ab02SPeter Avalos (*name_cache_variable)->size = name_cache_size; 13318029ab02SPeter Avalos } 13328029ab02SPeter Avalos 13338029ab02SPeter Avalos cache = *name_cache_variable; 13348029ab02SPeter Avalos cache->probes++; 13358029ab02SPeter Avalos 13368029ab02SPeter Avalos slot = id % cache->size; 13378029ab02SPeter Avalos if (cache->cache[slot].name != NULL) { 13388029ab02SPeter Avalos if (cache->cache[slot].id == id) { 13398029ab02SPeter Avalos cache->hits++; 13408029ab02SPeter Avalos return (cache->cache[slot].name); 13418029ab02SPeter Avalos } 13428029ab02SPeter Avalos free(cache->cache[slot].name); 13438029ab02SPeter Avalos cache->cache[slot].name = NULL; 13448029ab02SPeter Avalos } 13458029ab02SPeter Avalos 13468029ab02SPeter Avalos if (lookup_fn(cpio, &name, id) == 0) { 13478029ab02SPeter Avalos if (name == NULL || name[0] == '\0') { 13488029ab02SPeter Avalos /* If lookup failed, format it as a number. */ 13498029ab02SPeter Avalos snprintf(asnum, sizeof(asnum), "%u", (unsigned)id); 13508029ab02SPeter Avalos name = asnum; 13518029ab02SPeter Avalos } 13528029ab02SPeter Avalos cache->cache[slot].name = strdup(name); 13538029ab02SPeter Avalos if (cache->cache[slot].name != NULL) { 13548029ab02SPeter Avalos cache->cache[slot].id = id; 13558029ab02SPeter Avalos return (cache->cache[slot].name); 13568029ab02SPeter Avalos } 13578029ab02SPeter Avalos /* 13588029ab02SPeter Avalos * Conveniently, NULL marks an empty slot, so 13598029ab02SPeter Avalos * if the strdup() fails, we've just failed to 13608029ab02SPeter Avalos * cache it. No recovery necessary. 13618029ab02SPeter Avalos */ 13628029ab02SPeter Avalos } 13638029ab02SPeter Avalos return (NULL); 13648029ab02SPeter Avalos } 13658029ab02SPeter Avalos 13668029ab02SPeter Avalos static const char * 13678029ab02SPeter Avalos lookup_uname(struct cpio *cpio, uid_t uid) 13688029ab02SPeter Avalos { 13698029ab02SPeter Avalos return (lookup_name(cpio, &cpio->uname_cache, 13708029ab02SPeter Avalos &lookup_uname_helper, (id_t)uid)); 13718029ab02SPeter Avalos } 13728029ab02SPeter Avalos 13738029ab02SPeter Avalos static int 13748029ab02SPeter Avalos lookup_uname_helper(struct cpio *cpio, const char **name, id_t id) 13758029ab02SPeter Avalos { 13768029ab02SPeter Avalos struct passwd *pwent; 13778029ab02SPeter Avalos 13788029ab02SPeter Avalos (void)cpio; /* UNUSED */ 13798029ab02SPeter Avalos 13808029ab02SPeter Avalos errno = 0; 13818029ab02SPeter Avalos pwent = getpwuid((uid_t)id); 13828029ab02SPeter Avalos if (pwent == NULL) { 13838029ab02SPeter Avalos *name = NULL; 13849c82a63eSPeter Avalos if (errno != 0 && errno != ENOENT) 138559bf7050SPeter Avalos lafe_warnc(errno, "getpwuid(%s) failed", 138659bf7050SPeter Avalos cpio_i64toa((int64_t)id)); 13878029ab02SPeter Avalos return (errno); 13888029ab02SPeter Avalos } 13898029ab02SPeter Avalos 13908029ab02SPeter Avalos *name = pwent->pw_name; 13918029ab02SPeter Avalos return (0); 13928029ab02SPeter Avalos } 13938029ab02SPeter Avalos 13948029ab02SPeter Avalos static const char * 13958029ab02SPeter Avalos lookup_gname(struct cpio *cpio, gid_t gid) 13968029ab02SPeter Avalos { 13978029ab02SPeter Avalos return (lookup_name(cpio, &cpio->gname_cache, 13988029ab02SPeter Avalos &lookup_gname_helper, (id_t)gid)); 13998029ab02SPeter Avalos } 14008029ab02SPeter Avalos 14018029ab02SPeter Avalos static int 14028029ab02SPeter Avalos lookup_gname_helper(struct cpio *cpio, const char **name, id_t id) 14038029ab02SPeter Avalos { 14048029ab02SPeter Avalos struct group *grent; 14058029ab02SPeter Avalos 14068029ab02SPeter Avalos (void)cpio; /* UNUSED */ 14078029ab02SPeter Avalos 14088029ab02SPeter Avalos errno = 0; 14098029ab02SPeter Avalos grent = getgrgid((gid_t)id); 14108029ab02SPeter Avalos if (grent == NULL) { 14118029ab02SPeter Avalos *name = NULL; 14128029ab02SPeter Avalos if (errno != 0) 141359bf7050SPeter Avalos lafe_warnc(errno, "getgrgid(%s) failed", 141459bf7050SPeter Avalos cpio_i64toa((int64_t)id)); 14158029ab02SPeter Avalos return (errno); 14168029ab02SPeter Avalos } 14178029ab02SPeter Avalos 14188029ab02SPeter Avalos *name = grent->gr_name; 14198029ab02SPeter Avalos return (0); 14208029ab02SPeter Avalos } 14219c82a63eSPeter Avalos 14229c82a63eSPeter Avalos /* 14239c82a63eSPeter Avalos * It would be nice to just use printf() for formatting large numbers, 14249c82a63eSPeter Avalos * but the compatibility problems are a big headache. Hence the 14259c82a63eSPeter Avalos * following simple utility function. 14269c82a63eSPeter Avalos */ 14279c82a63eSPeter Avalos const char * 14289c82a63eSPeter Avalos cpio_i64toa(int64_t n0) 14299c82a63eSPeter Avalos { 1430c09f92d2SPeter Avalos /* 2^64 =~ 1.8 * 10^19, so 20 decimal digits suffice. 1431c09f92d2SPeter Avalos * We also need 1 byte for '-' and 1 for '\0'. 1432c09f92d2SPeter Avalos */ 14339c82a63eSPeter Avalos static char buff[22]; 14349c82a63eSPeter Avalos int64_t n = n0 < 0 ? -n0 : n0; 14359c82a63eSPeter Avalos char *p = buff + sizeof(buff); 14369c82a63eSPeter Avalos 14379c82a63eSPeter Avalos *--p = '\0'; 14389c82a63eSPeter Avalos do { 14399c82a63eSPeter Avalos *--p = '0' + (int)(n % 10); 14409c82a63eSPeter Avalos n /= 10; 14419c82a63eSPeter Avalos } while (n > 0); 14429c82a63eSPeter Avalos if (n0 < 0) 14439c82a63eSPeter Avalos *--p = '-'; 14449c82a63eSPeter Avalos return p; 14459c82a63eSPeter Avalos } 1446*6b384f39SPeter Avalos 1447*6b384f39SPeter Avalos #define PPBUFF_SIZE 1024 1448*6b384f39SPeter Avalos static const char * 1449*6b384f39SPeter Avalos passphrase_callback(struct archive *a, void *_client_data) 1450*6b384f39SPeter Avalos { 1451*6b384f39SPeter Avalos struct cpio *cpio = (struct cpio *)_client_data; 1452*6b384f39SPeter Avalos (void)a; /* UNUSED */ 1453*6b384f39SPeter Avalos 1454*6b384f39SPeter Avalos if (cpio->ppbuff == NULL) { 1455*6b384f39SPeter Avalos cpio->ppbuff = malloc(PPBUFF_SIZE); 1456*6b384f39SPeter Avalos if (cpio->ppbuff == NULL) 1457*6b384f39SPeter Avalos lafe_errc(1, errno, "Out of memory"); 1458*6b384f39SPeter Avalos } 1459*6b384f39SPeter Avalos return lafe_readpassphrase("Enter passphrase:", 1460*6b384f39SPeter Avalos cpio->ppbuff, PPBUFF_SIZE); 1461*6b384f39SPeter Avalos } 1462*6b384f39SPeter Avalos 1463*6b384f39SPeter Avalos static void 1464*6b384f39SPeter Avalos passphrase_free(char *ppbuff) 1465*6b384f39SPeter Avalos { 1466*6b384f39SPeter Avalos if (ppbuff != NULL) { 1467*6b384f39SPeter Avalos memset(ppbuff, 0, PPBUFF_SIZE); 1468*6b384f39SPeter Avalos free(ppbuff); 1469*6b384f39SPeter Avalos } 1470*6b384f39SPeter Avalos } 1471