1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3238856Smm * Copyright (c) 2012 Michihiro NAKAJIMA 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer. 11228753Smm * 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 "bsdtar_platform.h" 28228763Smm__FBSDID("$FreeBSD$"); 29228753Smm 30228753Smm#ifdef HAVE_SYS_TYPES_H 31228753Smm#include <sys/types.h> 32228753Smm#endif 33228753Smm#ifdef HAVE_SYS_STAT_H 34228753Smm#include <sys/stat.h> 35228753Smm#endif 36228753Smm#ifdef HAVE_ATTR_XATTR_H 37228753Smm#include <attr/xattr.h> 38228753Smm#endif 39228753Smm#ifdef HAVE_ERRNO_H 40228753Smm#include <errno.h> 41228753Smm#endif 42228753Smm#ifdef HAVE_FCNTL_H 43228753Smm#include <fcntl.h> 44228753Smm#endif 45228753Smm#ifdef HAVE_GRP_H 46228753Smm#include <grp.h> 47228753Smm#endif 48228753Smm#ifdef HAVE_IO_H 49228753Smm#include <io.h> 50228753Smm#endif 51232153Smm#ifdef HAVE_LIBGEN_H 52232153Smm#include <libgen.h> 53232153Smm#endif 54228753Smm#ifdef HAVE_LIMITS_H 55228753Smm#include <limits.h> 56228753Smm#endif 57232153Smm#ifdef HAVE_PATHS_H 58232153Smm#include <paths.h> 59232153Smm#endif 60228753Smm#ifdef HAVE_PWD_H 61228753Smm#include <pwd.h> 62228753Smm#endif 63228753Smm#ifdef HAVE_STDINT_H 64228753Smm#include <stdint.h> 65228753Smm#endif 66228753Smm#include <stdio.h> 67228753Smm#ifdef HAVE_STDLIB_H 68228753Smm#include <stdlib.h> 69228753Smm#endif 70228753Smm#ifdef HAVE_STRING_H 71228753Smm#include <string.h> 72228753Smm#endif 73228753Smm#ifdef HAVE_UNISTD_H 74228753Smm#include <unistd.h> 75228753Smm#endif 76228753Smm 77228753Smm#include "bsdtar.h" 78228753Smm#include "err.h" 79228753Smm#include "line_reader.h" 80228753Smm 81228753Smm#ifndef O_BINARY 82232153Smm#define O_BINARY 0 83228753Smm#endif 84228753Smm 85228753Smmstruct archive_dir_entry { 86228753Smm struct archive_dir_entry *next; 87228753Smm time_t mtime_sec; 88228753Smm int mtime_nsec; 89228753Smm char *name; 90228753Smm}; 91228753Smm 92228753Smmstruct archive_dir { 93228753Smm struct archive_dir_entry *head, *tail; 94228753Smm}; 95228753Smm 96228753Smmstatic int append_archive(struct bsdtar *, struct archive *, 97228753Smm struct archive *ina); 98228753Smmstatic int append_archive_filename(struct bsdtar *, 99228753Smm struct archive *, const char *fname); 100228753Smmstatic void archive_names_from_file(struct bsdtar *bsdtar, 101228753Smm struct archive *a); 102238856Smmstatic int copy_file_data_block(struct bsdtar *, 103238856Smm struct archive *a, struct archive *, 104238856Smm struct archive_entry *); 105238856Smmstatic void excluded_callback(struct archive *, void *, 106238856Smm struct archive_entry *); 107228753Smmstatic void report_write(struct bsdtar *, struct archive *, 108228753Smm struct archive_entry *, int64_t progress); 109228753Smmstatic void test_for_append(struct bsdtar *); 110238856Smmstatic int metadata_filter(struct archive *, void *, 111238856Smm struct archive_entry *); 112228753Smmstatic void write_archive(struct archive *, struct bsdtar *); 113232153Smmstatic void write_entry(struct bsdtar *, struct archive *, 114228753Smm struct archive_entry *); 115232153Smmstatic void write_file(struct bsdtar *, struct archive *, 116232153Smm struct archive_entry *); 117228753Smmstatic void write_hierarchy(struct bsdtar *, struct archive *, 118228753Smm const char *); 119228753Smm 120228753Smm#if defined(_WIN32) && !defined(__CYGWIN__) 121228753Smm/* Not a full lseek() emulation, but enough for our needs here. */ 122228753Smmstatic int 123228753Smmseek_file(int fd, int64_t offset, int whence) 124228753Smm{ 125228753Smm LARGE_INTEGER distance; 126228753Smm (void)whence; /* UNUSED */ 127228753Smm distance.QuadPart = offset; 128228753Smm return (SetFilePointerEx((HANDLE)_get_osfhandle(fd), 129228753Smm distance, NULL, FILE_BEGIN) ? 1 : -1); 130228753Smm} 131232153Smm#define open _open 132232153Smm#define close _close 133232153Smm#define read _read 134248616Smm#ifdef lseek 135248616Smm#undef lseek 136248616Smm#endif 137232153Smm#define lseek seek_file 138228753Smm#endif 139228753Smm 140248616Smmstatic void 141248616Smmset_writer_options(struct bsdtar *bsdtar, struct archive *a) 142248616Smm{ 143248616Smm const char *writer_options; 144248616Smm int r; 145248616Smm 146248616Smm writer_options = getenv(ENV_WRITER_OPTIONS); 147248616Smm if (writer_options != NULL) { 148248616Smm char *p; 149248616Smm /* Set default write options. */ 150248616Smm p = malloc(sizeof(IGNORE_WRONG_MODULE_NAME) 151248616Smm + strlen(writer_options) + 1); 152248616Smm if (p == NULL) 153248616Smm lafe_errc(1, errno, "Out of memory"); 154248616Smm /* Prepend magic code to ignore options for 155248616Smm * a format or filters which are not added to 156248616Smm * the archive write object. */ 157248616Smm strncpy(p, IGNORE_WRONG_MODULE_NAME, 158248616Smm sizeof(IGNORE_WRONG_MODULE_NAME) -1); 159248616Smm strcpy(p + sizeof(IGNORE_WRONG_MODULE_NAME) -1, writer_options); 160248616Smm r = archive_write_set_options(a, p); 161248616Smm free(p); 162248616Smm if (r < ARCHIVE_WARN) 163248616Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 164248616Smm else 165248616Smm archive_clear_error(a); 166248616Smm } 167248616Smm if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) 168248616Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 169248616Smm} 170248616Smm 171248616Smmstatic void 172248616Smmset_reader_options(struct bsdtar *bsdtar, struct archive *a) 173248616Smm{ 174248616Smm const char *reader_options; 175248616Smm int r; 176248616Smm 177248616Smm (void)bsdtar; /* UNUSED */ 178248616Smm 179248616Smm reader_options = getenv(ENV_READER_OPTIONS); 180248616Smm if (reader_options != NULL) { 181248616Smm char *p; 182248616Smm /* Set default write options. */ 183248616Smm p = malloc(sizeof(IGNORE_WRONG_MODULE_NAME) 184248616Smm + strlen(reader_options) + 1); 185248616Smm if (p == NULL) 186248616Smm lafe_errc(1, errno, "Out of memory"); 187248616Smm /* Prepend magic code to ignore options for 188248616Smm * a format or filters which are not added to 189248616Smm * the archive write object. */ 190248616Smm strncpy(p, IGNORE_WRONG_MODULE_NAME, 191248616Smm sizeof(IGNORE_WRONG_MODULE_NAME) -1); 192248616Smm strcpy(p + sizeof(IGNORE_WRONG_MODULE_NAME) -1, reader_options); 193248616Smm r = archive_read_set_options(a, p); 194248616Smm free(p); 195248616Smm if (r < ARCHIVE_WARN) 196248616Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 197248616Smm else 198248616Smm archive_clear_error(a); 199248616Smm } 200248616Smm} 201248616Smm 202228753Smmvoid 203228753Smmtar_mode_c(struct bsdtar *bsdtar) 204228753Smm{ 205228753Smm struct archive *a; 206248616Smm const void *filter_name; 207228753Smm int r; 208228753Smm 209228753Smm if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) 210228753Smm lafe_errc(1, 0, "no files or directories specified"); 211228753Smm 212228753Smm a = archive_write_new(); 213228753Smm 214228753Smm /* Support any format that the library supports. */ 215248616Smm if (cset_get_format(bsdtar->cset) == NULL) { 216228753Smm r = archive_write_set_format_pax_restricted(a); 217248616Smm cset_set_format(bsdtar->cset, "pax restricted"); 218228753Smm } else { 219248616Smm r = archive_write_set_format_by_name(a, 220248616Smm cset_get_format(bsdtar->cset)); 221228753Smm } 222228753Smm if (r != ARCHIVE_OK) { 223228753Smm fprintf(stderr, "Can't use format %s: %s\n", 224248616Smm cset_get_format(bsdtar->cset), 225228753Smm archive_error_string(a)); 226228753Smm usage(); 227228753Smm } 228228753Smm 229232153Smm archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); 230232153Smm archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); 231228753Smm 232248616Smm r = cset_write_add_filters(bsdtar->cset, a, &filter_name); 233248616Smm if (r < ARCHIVE_WARN) { 234248616Smm lafe_errc(1, 0, "Unsupported compression option --%s", 235248616Smm (const char *)filter_name); 236228753Smm } 237228753Smm 238248616Smm set_writer_options(bsdtar, a); 239248616Smm if (ARCHIVE_OK != archive_write_open_filename(a, bsdtar->filename)) 240228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 241228753Smm write_archive(a, bsdtar); 242228753Smm} 243228753Smm 244228753Smm/* 245228753Smm * Same as 'c', except we only support tar or empty formats in 246228753Smm * uncompressed files on disk. 247228753Smm */ 248228753Smmvoid 249228753Smmtar_mode_r(struct bsdtar *bsdtar) 250228753Smm{ 251228753Smm int64_t end_offset; 252228753Smm int format; 253228753Smm struct archive *a; 254228753Smm struct archive_entry *entry; 255228753Smm int r; 256228753Smm 257228753Smm /* Sanity-test some arguments and the file. */ 258228753Smm test_for_append(bsdtar); 259228753Smm 260228753Smm format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; 261228753Smm 262228753Smm#if defined(__BORLANDC__) 263228753Smm bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY); 264228753Smm#else 265228753Smm bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY, 0666); 266228753Smm#endif 267228753Smm if (bsdtar->fd < 0) 268228753Smm lafe_errc(1, errno, 269228753Smm "Cannot open %s", bsdtar->filename); 270228753Smm 271228753Smm a = archive_read_new(); 272232153Smm archive_read_support_filter_all(a); 273239622Smm archive_read_support_format_empty(a); 274228753Smm archive_read_support_format_tar(a); 275228753Smm archive_read_support_format_gnutar(a); 276248616Smm set_reader_options(bsdtar, a); 277228753Smm r = archive_read_open_fd(a, bsdtar->fd, 10240); 278228753Smm if (r != ARCHIVE_OK) 279228753Smm lafe_errc(1, archive_errno(a), 280228753Smm "Can't read archive %s: %s", bsdtar->filename, 281228753Smm archive_error_string(a)); 282228753Smm while (0 == archive_read_next_header(a, &entry)) { 283248616Smm if (archive_filter_code(a, 0) != ARCHIVE_FILTER_NONE) { 284232153Smm archive_read_free(a); 285228753Smm close(bsdtar->fd); 286228753Smm lafe_errc(1, 0, 287228753Smm "Cannot append to compressed archive."); 288228753Smm } 289228753Smm /* Keep going until we hit end-of-archive */ 290228753Smm format = archive_format(a); 291228753Smm } 292228753Smm 293228753Smm end_offset = archive_read_header_position(a); 294232153Smm archive_read_free(a); 295228753Smm 296228753Smm /* Re-open archive for writing */ 297228753Smm a = archive_write_new(); 298228753Smm /* 299228753Smm * Set the format to be used for writing. To allow people to 300228753Smm * extend empty files, we need to allow them to specify the format, 301228753Smm * which opens the possibility that they will specify a format that 302228753Smm * doesn't match the existing format. Hence, the following bit 303228753Smm * of arcane ugliness. 304228753Smm */ 305228753Smm 306248616Smm if (cset_get_format(bsdtar->cset) != NULL) { 307228753Smm /* If the user requested a format, use that, but ... */ 308228753Smm archive_write_set_format_by_name(a, 309248616Smm cset_get_format(bsdtar->cset)); 310228753Smm /* ... complain if it's not compatible. */ 311228753Smm format &= ARCHIVE_FORMAT_BASE_MASK; 312228753Smm if (format != (int)(archive_format(a) & ARCHIVE_FORMAT_BASE_MASK) 313228753Smm && format != ARCHIVE_FORMAT_EMPTY) { 314228753Smm lafe_errc(1, 0, 315228753Smm "Format %s is incompatible with the archive %s.", 316248616Smm cset_get_format(bsdtar->cset), bsdtar->filename); 317228753Smm } 318228753Smm } else { 319228753Smm /* 320228753Smm * Just preserve the current format, with a little care 321228753Smm * for formats that libarchive can't write. 322228753Smm */ 323228753Smm if (format == ARCHIVE_FORMAT_EMPTY) 324228753Smm format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; 325228753Smm archive_write_set_format(a, format); 326228753Smm } 327228753Smm if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0) 328228753Smm lafe_errc(1, errno, "Could not seek to archive end"); 329248616Smm set_writer_options(bsdtar, a); 330228753Smm if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd)) 331228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 332228753Smm 333228753Smm write_archive(a, bsdtar); /* XXX check return val XXX */ 334228753Smm 335228753Smm close(bsdtar->fd); 336228753Smm bsdtar->fd = -1; 337228753Smm} 338228753Smm 339228753Smmvoid 340228753Smmtar_mode_u(struct bsdtar *bsdtar) 341228753Smm{ 342228753Smm int64_t end_offset; 343228753Smm struct archive *a; 344228753Smm struct archive_entry *entry; 345228753Smm int format; 346228753Smm struct archive_dir_entry *p; 347228753Smm struct archive_dir archive_dir; 348228753Smm 349228753Smm bsdtar->archive_dir = &archive_dir; 350228753Smm memset(&archive_dir, 0, sizeof(archive_dir)); 351228753Smm 352228753Smm format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; 353228753Smm 354228753Smm /* Sanity-test some arguments and the file. */ 355228753Smm test_for_append(bsdtar); 356228753Smm 357228753Smm bsdtar->fd = open(bsdtar->filename, O_RDWR | O_BINARY); 358228753Smm if (bsdtar->fd < 0) 359228753Smm lafe_errc(1, errno, 360228753Smm "Cannot open %s", bsdtar->filename); 361228753Smm 362228753Smm a = archive_read_new(); 363232153Smm archive_read_support_filter_all(a); 364228753Smm archive_read_support_format_tar(a); 365228753Smm archive_read_support_format_gnutar(a); 366248616Smm set_reader_options(bsdtar, a); 367232153Smm if (archive_read_open_fd(a, bsdtar->fd, bsdtar->bytes_per_block) 368232153Smm != ARCHIVE_OK) { 369228753Smm lafe_errc(1, 0, 370228753Smm "Can't open %s: %s", bsdtar->filename, 371228753Smm archive_error_string(a)); 372228753Smm } 373228753Smm 374228753Smm /* Build a list of all entries and their recorded mod times. */ 375228753Smm while (0 == archive_read_next_header(a, &entry)) { 376248616Smm if (archive_filter_code(a, 0) != ARCHIVE_FILTER_NONE) { 377232153Smm archive_read_free(a); 378228753Smm close(bsdtar->fd); 379228753Smm lafe_errc(1, 0, 380228753Smm "Cannot append to compressed archive."); 381228753Smm } 382238856Smm if (archive_match_exclude_entry(bsdtar->matching, 383238856Smm ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER | 384238856Smm ARCHIVE_MATCH_EQUAL, entry) != ARCHIVE_OK) 385238856Smm lafe_errc(1, 0, "Error : %s", 386238856Smm archive_error_string(bsdtar->matching)); 387228753Smm /* Record the last format determination we see */ 388228753Smm format = archive_format(a); 389228753Smm /* Keep going until we hit end-of-archive */ 390228753Smm } 391228753Smm 392228753Smm end_offset = archive_read_header_position(a); 393232153Smm archive_read_free(a); 394228753Smm 395228753Smm /* Re-open archive for writing. */ 396228753Smm a = archive_write_new(); 397228753Smm /* 398232153Smm * Set format to same one auto-detected above. 399228753Smm */ 400228753Smm archive_write_set_format(a, format); 401232153Smm archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); 402232153Smm archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); 403232153Smm 404228753Smm if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0) 405228753Smm lafe_errc(1, errno, "Could not seek to archive end"); 406248616Smm set_writer_options(bsdtar, a); 407228753Smm if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd)) 408228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 409228753Smm 410228753Smm write_archive(a, bsdtar); 411228753Smm 412228753Smm close(bsdtar->fd); 413228753Smm bsdtar->fd = -1; 414228753Smm 415228753Smm while (bsdtar->archive_dir->head != NULL) { 416228753Smm p = bsdtar->archive_dir->head->next; 417228753Smm free(bsdtar->archive_dir->head->name); 418228753Smm free(bsdtar->archive_dir->head); 419228753Smm bsdtar->archive_dir->head = p; 420228753Smm } 421228753Smm bsdtar->archive_dir->tail = NULL; 422228753Smm} 423228753Smm 424228753Smm 425228753Smm/* 426228753Smm * Write user-specified files/dirs to opened archive. 427228753Smm */ 428228753Smmstatic void 429228753Smmwrite_archive(struct archive *a, struct bsdtar *bsdtar) 430228753Smm{ 431228753Smm const char *arg; 432228753Smm struct archive_entry *entry, *sparse_entry; 433228753Smm 434232153Smm /* Choose a suitable copy buffer size */ 435232153Smm bsdtar->buff_size = 64 * 1024; 436232153Smm while (bsdtar->buff_size < (size_t)bsdtar->bytes_per_block) 437232153Smm bsdtar->buff_size *= 2; 438232153Smm /* Try to compensate for space we'll lose to alignment. */ 439232153Smm bsdtar->buff_size += 16 * 1024; 440232153Smm 441228753Smm /* Allocate a buffer for file data. */ 442232153Smm if ((bsdtar->buff = malloc(bsdtar->buff_size)) == NULL) 443228753Smm lafe_errc(1, 0, "cannot allocate memory"); 444228753Smm 445228753Smm if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL) 446228753Smm lafe_errc(1, 0, "cannot create link resolver"); 447228753Smm archive_entry_linkresolver_set_strategy(bsdtar->resolver, 448228753Smm archive_format(a)); 449238856Smm 450238856Smm /* Create a read_disk object. */ 451228753Smm if ((bsdtar->diskreader = archive_read_disk_new()) == NULL) 452228753Smm lafe_errc(1, 0, "Cannot create read_disk object"); 453238856Smm /* Tell the read_disk how handle symlink. */ 454238856Smm switch (bsdtar->symlink_mode) { 455238856Smm case 'H': 456238856Smm archive_read_disk_set_symlink_hybrid(bsdtar->diskreader); 457238856Smm break; 458238856Smm case 'L': 459238856Smm archive_read_disk_set_symlink_logical(bsdtar->diskreader); 460238856Smm break; 461238856Smm default: 462238856Smm archive_read_disk_set_symlink_physical(bsdtar->diskreader); 463238856Smm break; 464238856Smm } 465238856Smm /* Register entry filters. */ 466238856Smm archive_read_disk_set_matching(bsdtar->diskreader, 467238856Smm bsdtar->matching, excluded_callback, bsdtar); 468238856Smm archive_read_disk_set_metadata_filter_callback( 469238856Smm bsdtar->diskreader, metadata_filter, bsdtar); 470238856Smm /* Set the behavior of archive_read_disk. */ 471238856Smm archive_read_disk_set_behavior(bsdtar->diskreader, 472238856Smm bsdtar->readdisk_flags); 473228753Smm archive_read_disk_set_standard_lookup(bsdtar->diskreader); 474228753Smm 475228753Smm if (bsdtar->names_from_file != NULL) 476228753Smm archive_names_from_file(bsdtar, a); 477228753Smm 478228753Smm while (*bsdtar->argv) { 479228753Smm arg = *bsdtar->argv; 480228753Smm if (arg[0] == '-' && arg[1] == 'C') { 481228753Smm arg += 2; 482228753Smm if (*arg == '\0') { 483228753Smm bsdtar->argv++; 484228753Smm arg = *bsdtar->argv; 485228753Smm if (arg == NULL) { 486228753Smm lafe_warnc(0, "%s", 487228753Smm "Missing argument for -C"); 488228753Smm bsdtar->return_value = 1; 489228753Smm goto cleanup; 490228753Smm } 491232153Smm if (*arg == '\0') { 492232153Smm lafe_warnc(0, 493232153Smm "Meaningless argument for -C: ''"); 494232153Smm bsdtar->return_value = 1; 495232153Smm goto cleanup; 496232153Smm } 497228753Smm } 498228753Smm set_chdir(bsdtar, arg); 499228753Smm } else { 500228753Smm if (*arg != '/' && (arg[0] != '@' || arg[1] != '/')) 501228753Smm do_chdir(bsdtar); /* Handle a deferred -C */ 502228753Smm if (*arg == '@') { 503228753Smm if (append_archive_filename(bsdtar, a, 504228753Smm arg + 1) != 0) 505228753Smm break; 506228753Smm } else 507228753Smm write_hierarchy(bsdtar, a, arg); 508228753Smm } 509228753Smm bsdtar->argv++; 510228753Smm } 511228753Smm 512238856Smm archive_read_disk_set_matching(bsdtar->diskreader, NULL, NULL, NULL); 513238856Smm archive_read_disk_set_metadata_filter_callback( 514238856Smm bsdtar->diskreader, NULL, NULL); 515228753Smm entry = NULL; 516228753Smm archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); 517228753Smm while (entry != NULL) { 518238856Smm int r; 519238856Smm struct archive_entry *entry2; 520238856Smm struct archive *disk = bsdtar->diskreader; 521238856Smm 522238856Smm /* 523238856Smm * This tricky code here is to correctly read the cotents 524238856Smm * of the entry because the disk reader bsdtar->diskreader 525238856Smm * is pointing at does not have any information about the 526238856Smm * entry by this time and using archive_read_data_block() 527238856Smm * with the disk reader consequently must fail. And we 528238856Smm * have to re-open the entry to read the contents. 529238856Smm */ 530238856Smm /* TODO: Work with -C option as well. */ 531238856Smm r = archive_read_disk_open(disk, 532238856Smm archive_entry_sourcepath(entry)); 533238856Smm if (r != ARCHIVE_OK) { 534238856Smm lafe_warnc(archive_errno(disk), 535238856Smm "%s", archive_error_string(disk)); 536238856Smm bsdtar->return_value = 1; 537238856Smm archive_entry_free(entry); 538238856Smm continue; 539238856Smm } 540238856Smm 541238856Smm /* 542238856Smm * Invoke archive_read_next_header2() to work 543238856Smm * archive_read_data_block(), which is called via write_file(), 544238856Smm * without failure. 545238856Smm */ 546238856Smm entry2 = archive_entry_new(); 547238856Smm r = archive_read_next_header2(disk, entry2); 548238856Smm archive_entry_free(entry2); 549238856Smm if (r != ARCHIVE_OK) { 550238856Smm lafe_warnc(archive_errno(disk), 551238856Smm "%s", archive_error_string(disk)); 552238856Smm if (r == ARCHIVE_FATAL) 553238856Smm bsdtar->return_value = 1; 554238856Smm else 555238856Smm archive_read_close(disk); 556238856Smm archive_entry_free(entry); 557238856Smm continue; 558238856Smm } 559238856Smm 560232153Smm write_file(bsdtar, a, entry); 561228753Smm archive_entry_free(entry); 562238856Smm archive_read_close(disk); 563228753Smm entry = NULL; 564228753Smm archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); 565228753Smm } 566228753Smm 567228753Smm if (archive_write_close(a)) { 568228753Smm lafe_warnc(0, "%s", archive_error_string(a)); 569228753Smm bsdtar->return_value = 1; 570228753Smm } 571228753Smm 572228753Smmcleanup: 573228753Smm /* Free file data buffer. */ 574228753Smm free(bsdtar->buff); 575228753Smm archive_entry_linkresolver_free(bsdtar->resolver); 576228753Smm bsdtar->resolver = NULL; 577232153Smm archive_read_free(bsdtar->diskreader); 578228753Smm bsdtar->diskreader = NULL; 579228753Smm 580228753Smm if (bsdtar->option_totals) { 581228753Smm fprintf(stderr, "Total bytes written: %s\n", 582248616Smm tar_i64toa(archive_filter_bytes(a, -1))); 583228753Smm } 584228753Smm 585232153Smm archive_write_free(a); 586228753Smm} 587228753Smm 588228753Smm/* 589228753Smm * Archive names specified in file. 590228753Smm * 591228753Smm * Unless --null was specified, a line containing exactly "-C" will 592228753Smm * cause the next line to be a directory to pass to chdir(). If 593228753Smm * --null is specified, then a line "-C" is just another filename. 594228753Smm */ 595228753Smmstatic void 596228753Smmarchive_names_from_file(struct bsdtar *bsdtar, struct archive *a) 597228753Smm{ 598228753Smm struct lafe_line_reader *lr; 599228753Smm const char *line; 600228753Smm 601228753Smm bsdtar->next_line_is_dir = 0; 602228753Smm 603228753Smm lr = lafe_line_reader(bsdtar->names_from_file, bsdtar->option_null); 604228753Smm while ((line = lafe_line_reader_next(lr)) != NULL) { 605228753Smm if (bsdtar->next_line_is_dir) { 606232153Smm if (*line != '\0') 607232153Smm set_chdir(bsdtar, line); 608232153Smm else { 609232153Smm lafe_warnc(0, 610232153Smm "Meaningless argument for -C: ''"); 611232153Smm bsdtar->return_value = 1; 612232153Smm } 613228753Smm bsdtar->next_line_is_dir = 0; 614228753Smm } else if (!bsdtar->option_null && strcmp(line, "-C") == 0) 615228753Smm bsdtar->next_line_is_dir = 1; 616228753Smm else { 617228753Smm if (*line != '/') 618228753Smm do_chdir(bsdtar); /* Handle a deferred -C */ 619228753Smm write_hierarchy(bsdtar, a, line); 620228753Smm } 621228753Smm } 622228753Smm lafe_line_reader_free(lr); 623228753Smm if (bsdtar->next_line_is_dir) 624228753Smm lafe_errc(1, errno, 625228753Smm "Unexpected end of filename list; " 626228753Smm "directory expected after -C"); 627228753Smm} 628228753Smm 629228753Smm/* 630228753Smm * Copy from specified archive to current archive. Returns non-zero 631228753Smm * for write errors (which force us to terminate the entire archiving 632228753Smm * operation). If there are errors reading the input archive, we set 633228753Smm * bsdtar->return_value but return zero, so the overall archiving 634228753Smm * operation will complete and return non-zero. 635228753Smm */ 636228753Smmstatic int 637228753Smmappend_archive_filename(struct bsdtar *bsdtar, struct archive *a, 638232153Smm const char *raw_filename) 639228753Smm{ 640228753Smm struct archive *ina; 641232153Smm const char *filename = raw_filename; 642228753Smm int rc; 643228753Smm 644228753Smm if (strcmp(filename, "-") == 0) 645228753Smm filename = NULL; /* Library uses NULL for stdio. */ 646228753Smm 647228753Smm ina = archive_read_new(); 648228753Smm archive_read_support_format_all(ina); 649232153Smm archive_read_support_filter_all(ina); 650248616Smm set_reader_options(bsdtar, a); 651248616Smm if (archive_read_open_filename(ina, filename, 652248616Smm bsdtar->bytes_per_block)) { 653228753Smm lafe_warnc(0, "%s", archive_error_string(ina)); 654228753Smm bsdtar->return_value = 1; 655228753Smm return (0); 656228753Smm } 657228753Smm 658228753Smm rc = append_archive(bsdtar, a, ina); 659228753Smm 660228753Smm if (rc != ARCHIVE_OK) { 661228753Smm lafe_warnc(0, "Error reading archive %s: %s", 662232153Smm raw_filename, archive_error_string(ina)); 663228753Smm bsdtar->return_value = 1; 664228753Smm } 665232153Smm archive_read_free(ina); 666228753Smm 667228753Smm return (rc); 668228753Smm} 669228753Smm 670228753Smmstatic int 671228753Smmappend_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) 672228753Smm{ 673228753Smm struct archive_entry *in_entry; 674228753Smm int e; 675228753Smm 676228753Smm while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) { 677238856Smm if (archive_match_excluded(bsdtar->matching, in_entry)) 678228753Smm continue; 679228753Smm if (bsdtar->option_interactive && 680228753Smm !yes("copy '%s'", archive_entry_pathname(in_entry))) 681228753Smm continue; 682228753Smm if (bsdtar->verbose) 683228753Smm safe_fprintf(stderr, "a %s", 684228753Smm archive_entry_pathname(in_entry)); 685228753Smm if (need_report()) 686228753Smm report_write(bsdtar, a, in_entry, 0); 687228753Smm 688228753Smm e = archive_write_header(a, in_entry); 689228753Smm if (e != ARCHIVE_OK) { 690228753Smm if (!bsdtar->verbose) 691228753Smm lafe_warnc(0, "%s: %s", 692228753Smm archive_entry_pathname(in_entry), 693228753Smm archive_error_string(a)); 694228753Smm else 695228753Smm fprintf(stderr, ": %s", archive_error_string(a)); 696228753Smm } 697228753Smm if (e == ARCHIVE_FATAL) 698228753Smm exit(1); 699228753Smm 700228753Smm if (e >= ARCHIVE_WARN) { 701228753Smm if (archive_entry_size(in_entry) == 0) 702228753Smm archive_read_data_skip(ina); 703238856Smm else if (copy_file_data_block(bsdtar, a, ina, in_entry)) 704228753Smm exit(1); 705228753Smm } 706228753Smm 707228753Smm if (bsdtar->verbose) 708228753Smm fprintf(stderr, "\n"); 709228753Smm } 710228753Smm 711228753Smm return (e == ARCHIVE_EOF ? ARCHIVE_OK : e); 712228753Smm} 713228753Smm 714238856Smm/* Helper function to copy file to archive. */ 715228753Smmstatic int 716238856Smmcopy_file_data_block(struct bsdtar *bsdtar, struct archive *a, 717238856Smm struct archive *in_a, struct archive_entry *entry) 718228753Smm{ 719238856Smm size_t bytes_read; 720228753Smm ssize_t bytes_written; 721238856Smm int64_t offset, progress = 0; 722238856Smm char *null_buff = NULL; 723238856Smm const void *buff; 724238856Smm int r; 725228753Smm 726238856Smm while ((r = archive_read_data_block(in_a, &buff, 727238856Smm &bytes_read, &offset)) == ARCHIVE_OK) { 728228753Smm if (need_report()) 729228753Smm report_write(bsdtar, a, entry, progress); 730228753Smm 731238856Smm if (offset > progress) { 732238856Smm int64_t sparse = offset - progress; 733238856Smm size_t ns; 734238856Smm 735238856Smm if (null_buff == NULL) { 736238856Smm null_buff = bsdtar->buff; 737238856Smm memset(null_buff, 0, bsdtar->buff_size); 738238856Smm } 739238856Smm 740238856Smm while (sparse > 0) { 741238856Smm if (sparse > (int64_t)bsdtar->buff_size) 742238856Smm ns = bsdtar->buff_size; 743238856Smm else 744238856Smm ns = (size_t)sparse; 745238856Smm bytes_written = 746238856Smm archive_write_data(a, null_buff, ns); 747238856Smm if (bytes_written < 0) { 748238856Smm /* Write failed; this is bad */ 749238856Smm lafe_warnc(0, "%s", 750238856Smm archive_error_string(a)); 751238856Smm return (-1); 752238856Smm } 753238856Smm if ((size_t)bytes_written < ns) { 754238856Smm /* Write was truncated; warn but 755238856Smm * continue. */ 756238856Smm lafe_warnc(0, 757238856Smm "%s: Truncated write; file may " 758238856Smm "have grown while being archived.", 759238856Smm archive_entry_pathname(entry)); 760238856Smm return (0); 761238856Smm } 762238856Smm progress += bytes_written; 763238856Smm sparse -= bytes_written; 764238856Smm } 765238856Smm } 766238856Smm 767238856Smm bytes_written = archive_write_data(a, buff, bytes_read); 768238856Smm if (bytes_written < 0) { 769238856Smm /* Write failed; this is bad */ 770228753Smm lafe_warnc(0, "%s", archive_error_string(a)); 771228753Smm return (-1); 772228753Smm } 773238856Smm if ((size_t)bytes_written < bytes_read) { 774238856Smm /* Write was truncated; warn but continue. */ 775238856Smm lafe_warnc(0, 776238856Smm "%s: Truncated write; file may have grown " 777238856Smm "while being archived.", 778238856Smm archive_entry_pathname(entry)); 779238856Smm return (0); 780238856Smm } 781228753Smm progress += bytes_written; 782228753Smm } 783238856Smm if (r < ARCHIVE_WARN) { 784238856Smm lafe_warnc(archive_errno(a), "%s", archive_error_string(a)); 785238856Smm return (-1); 786238856Smm } 787228753Smm return (0); 788228753Smm} 789228753Smm 790238856Smmstatic void 791238856Smmexcluded_callback(struct archive *a, void *_data, struct archive_entry *entry) 792238856Smm{ 793238856Smm struct bsdtar *bsdtar = (struct bsdtar *)_data; 794238856Smm 795238856Smm if (bsdtar->option_no_subdirs) 796238856Smm return; 797238856Smm if (!archive_read_disk_can_descend(a)) 798238856Smm return; 799238856Smm if (bsdtar->option_interactive && 800238856Smm !yes("add '%s'", archive_entry_pathname(entry))) 801238856Smm return; 802238856Smm archive_read_disk_descend(a); 803238856Smm} 804238856Smm 805238856Smmstatic int 806238856Smmmetadata_filter(struct archive *a, void *_data, struct archive_entry *entry) 807238856Smm{ 808238856Smm struct bsdtar *bsdtar = (struct bsdtar *)_data; 809238856Smm 810238856Smm /* XXX TODO: check whether this filesystem is 811238856Smm * synthetic and/or local. Add a new 812238856Smm * --local-only option to skip non-local 813238856Smm * filesystems. Skip synthetic filesystems 814238856Smm * regardless. 815238856Smm * 816238856Smm * The results should be cached, since 817238856Smm * tree.c doesn't usually visit a directory 818238856Smm * and the directory contents together. A simple 819238856Smm * move-to-front list should perform quite well. 820238856Smm * 821238856Smm * Use archive_read_disk_current_filesystem_is_remote(). 822238856Smm */ 823238856Smm 824238856Smm /* 825238856Smm * If the user vetoes this file/directory, skip it. 826238856Smm * We want this to be fairly late; if some other 827238856Smm * check would veto this file, we shouldn't bother 828238856Smm * the user with it. 829238856Smm */ 830238856Smm if (bsdtar->option_interactive && 831238856Smm !yes("add '%s'", archive_entry_pathname(entry))) 832238856Smm return (0); 833238856Smm 834238856Smm /* Note: if user vetoes, we won't descend. */ 835238856Smm if (!bsdtar->option_no_subdirs && archive_read_disk_can_descend(a)) 836238856Smm archive_read_disk_descend(a); 837238856Smm 838238856Smm return (1); 839238856Smm} 840238856Smm 841228753Smm/* 842228753Smm * Add the file or dir hierarchy named by 'path' to the archive 843228753Smm */ 844228753Smmstatic void 845228753Smmwrite_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) 846228753Smm{ 847238856Smm struct archive *disk = bsdtar->diskreader; 848228753Smm struct archive_entry *entry = NULL, *spare_entry = NULL; 849238856Smm int r; 850228753Smm 851238856Smm r = archive_read_disk_open(disk, path); 852238856Smm if (r != ARCHIVE_OK) { 853238856Smm lafe_warnc(archive_errno(disk), 854238856Smm "%s", archive_error_string(disk)); 855228753Smm bsdtar->return_value = 1; 856228753Smm return; 857228753Smm } 858238856Smm bsdtar->first_fs = -1; 859228753Smm 860238856Smm for (;;) { 861238856Smm archive_entry_free(entry); 862238856Smm entry = archive_entry_new(); 863238856Smm r = archive_read_next_header2(disk, entry); 864238856Smm if (r == ARCHIVE_EOF) 865228753Smm break; 866238856Smm else if (r != ARCHIVE_OK) { 867238856Smm lafe_warnc(archive_errno(disk), 868238856Smm "%s", archive_error_string(disk)); 869238856Smm if (r == ARCHIVE_FATAL) { 870238856Smm bsdtar->return_value = 1; 871238856Smm return; 872238856Smm } else if (r < ARCHIVE_WARN) 873228776Smm continue; 874228776Smm } 875228753Smm 876228753Smm if (bsdtar->uid >= 0) { 877228753Smm archive_entry_set_uid(entry, bsdtar->uid); 878228753Smm if (!bsdtar->uname) 879228753Smm archive_entry_set_uname(entry, 880228753Smm archive_read_disk_uname(bsdtar->diskreader, 881228753Smm bsdtar->uid)); 882228753Smm } 883228753Smm if (bsdtar->gid >= 0) { 884228753Smm archive_entry_set_gid(entry, bsdtar->gid); 885228753Smm if (!bsdtar->gname) 886228753Smm archive_entry_set_gname(entry, 887228753Smm archive_read_disk_gname(bsdtar->diskreader, 888228753Smm bsdtar->gid)); 889228753Smm } 890228753Smm if (bsdtar->uname) 891228753Smm archive_entry_set_uname(entry, bsdtar->uname); 892228753Smm if (bsdtar->gname) 893228753Smm archive_entry_set_gname(entry, bsdtar->gname); 894228753Smm 895228753Smm /* 896228753Smm * Rewrite the pathname to be archived. If rewrite 897228753Smm * fails, skip the entry. 898228753Smm */ 899228753Smm if (edit_pathname(bsdtar, entry)) 900228753Smm continue; 901228753Smm 902228753Smm /* Display entry as we process it. 903228753Smm * This format is required by SUSv2. */ 904228753Smm if (bsdtar->verbose) 905228753Smm safe_fprintf(stderr, "a %s", 906228753Smm archive_entry_pathname(entry)); 907228753Smm 908228753Smm /* Non-regular files get archived with zero size. */ 909228753Smm if (archive_entry_filetype(entry) != AE_IFREG) 910228753Smm archive_entry_set_size(entry, 0); 911228753Smm 912228753Smm archive_entry_linkify(bsdtar->resolver, &entry, &spare_entry); 913228753Smm 914228753Smm while (entry != NULL) { 915232153Smm write_file(bsdtar, a, entry); 916228753Smm archive_entry_free(entry); 917228753Smm entry = spare_entry; 918228753Smm spare_entry = NULL; 919228753Smm } 920228753Smm 921228753Smm if (bsdtar->verbose) 922228753Smm fprintf(stderr, "\n"); 923228753Smm } 924228753Smm archive_entry_free(entry); 925238856Smm archive_read_close(disk); 926228753Smm} 927228753Smm 928228753Smm/* 929232153Smm * Write a single file (or directory or other filesystem object) to 930232153Smm * the archive. 931228753Smm */ 932228753Smmstatic void 933232153Smmwrite_file(struct bsdtar *bsdtar, struct archive *a, 934228753Smm struct archive_entry *entry) 935228753Smm{ 936232153Smm write_entry(bsdtar, a, entry); 937232153Smm} 938232153Smm 939232153Smm/* 940232153Smm * Write a single entry to the archive. 941232153Smm */ 942232153Smmstatic void 943232153Smmwrite_entry(struct bsdtar *bsdtar, struct archive *a, 944232153Smm struct archive_entry *entry) 945232153Smm{ 946228753Smm int e; 947228753Smm 948228753Smm e = archive_write_header(a, entry); 949228753Smm if (e != ARCHIVE_OK) { 950228753Smm if (!bsdtar->verbose) 951228753Smm lafe_warnc(0, "%s: %s", 952228753Smm archive_entry_pathname(entry), 953228753Smm archive_error_string(a)); 954228753Smm else 955228753Smm fprintf(stderr, ": %s", archive_error_string(a)); 956228753Smm } 957228753Smm 958228753Smm if (e == ARCHIVE_FATAL) 959228753Smm exit(1); 960228753Smm 961228753Smm /* 962228753Smm * If we opened a file earlier, write it out now. Note that 963228753Smm * the format handler might have reset the size field to zero 964228753Smm * to inform us that the archive body won't get stored. In 965228753Smm * that case, just skip the write. 966228753Smm */ 967238856Smm if (e >= ARCHIVE_WARN && archive_entry_size(entry) > 0) { 968238856Smm if (copy_file_data_block(bsdtar, a, bsdtar->diskreader, entry)) 969228753Smm exit(1); 970228753Smm } 971228753Smm} 972228753Smm 973228753Smmstatic void 974228753Smmreport_write(struct bsdtar *bsdtar, struct archive *a, 975228753Smm struct archive_entry *entry, int64_t progress) 976228753Smm{ 977228753Smm uint64_t comp, uncomp; 978228776Smm int compression; 979228776Smm 980228753Smm if (bsdtar->verbose) 981228753Smm fprintf(stderr, "\n"); 982248616Smm comp = archive_filter_bytes(a, -1); 983248616Smm uncomp = archive_filter_bytes(a, 0); 984228753Smm fprintf(stderr, "In: %d files, %s bytes;", 985228753Smm archive_file_count(a), tar_i64toa(uncomp)); 986228776Smm if (comp > uncomp) 987228776Smm compression = 0; 988228776Smm else 989228776Smm compression = (int)((uncomp - comp) * 100 / uncomp); 990228753Smm fprintf(stderr, 991228753Smm " Out: %s bytes, compression %d%%\n", 992228776Smm tar_i64toa(comp), compression); 993228753Smm /* Can't have two calls to tar_i64toa() pending, so split the output. */ 994228753Smm safe_fprintf(stderr, "Current: %s (%s", 995228753Smm archive_entry_pathname(entry), 996228753Smm tar_i64toa(progress)); 997228753Smm fprintf(stderr, "/%s bytes)\n", 998228753Smm tar_i64toa(archive_entry_size(entry))); 999228753Smm} 1000228753Smm 1001228753Smmstatic void 1002228753Smmtest_for_append(struct bsdtar *bsdtar) 1003228753Smm{ 1004228753Smm struct stat s; 1005228753Smm 1006228753Smm if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) 1007228753Smm lafe_errc(1, 0, "no files or directories specified"); 1008228753Smm if (bsdtar->filename == NULL) 1009228753Smm lafe_errc(1, 0, "Cannot append to stdout."); 1010228753Smm 1011228753Smm if (stat(bsdtar->filename, &s) != 0) 1012228753Smm return; 1013228753Smm 1014228753Smm if (!S_ISREG(s.st_mode) && !S_ISBLK(s.st_mode)) 1015228753Smm lafe_errc(1, 0, 1016228753Smm "Cannot append to %s: not a regular file.", 1017228753Smm bsdtar->filename); 1018228753Smm 1019228753Smm/* Is this an appropriate check here on Windows? */ 1020228753Smm/* 1021228753Smm if (GetFileType(handle) != FILE_TYPE_DISK) 1022228753Smm lafe_errc(1, 0, "Cannot append"); 1023228753Smm*/ 1024228753Smm 1025228753Smm} 1026