write.c revision 239622
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: head/contrib/libarchive/tar/write.c 239622 2012-08-23 19:40:28Z mm $"); 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 134232153Smm#define lseek seek_file 135228753Smm#endif 136228753Smm 137228753Smmvoid 138228753Smmtar_mode_c(struct bsdtar *bsdtar) 139228753Smm{ 140228753Smm struct archive *a; 141228753Smm int r; 142228753Smm 143228753Smm if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) 144228753Smm lafe_errc(1, 0, "no files or directories specified"); 145228753Smm 146228753Smm a = archive_write_new(); 147228753Smm 148228753Smm /* Support any format that the library supports. */ 149228753Smm if (bsdtar->create_format == NULL) { 150228753Smm r = archive_write_set_format_pax_restricted(a); 151228753Smm bsdtar->create_format = "pax restricted"; 152228753Smm } else { 153228753Smm r = archive_write_set_format_by_name(a, bsdtar->create_format); 154228753Smm } 155228753Smm if (r != ARCHIVE_OK) { 156228753Smm fprintf(stderr, "Can't use format %s: %s\n", 157228753Smm bsdtar->create_format, 158228753Smm archive_error_string(a)); 159228753Smm usage(); 160228753Smm } 161228753Smm 162232153Smm archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); 163232153Smm archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); 164228753Smm 165228753Smm if (bsdtar->compress_program) { 166228753Smm archive_write_set_compression_program(a, bsdtar->compress_program); 167228753Smm } else { 168228753Smm switch (bsdtar->create_compression) { 169228753Smm case 0: 170232153Smm r = ARCHIVE_OK; 171228753Smm break; 172228753Smm case 'j': case 'y': 173228753Smm r = archive_write_set_compression_bzip2(a); 174228753Smm break; 175228753Smm case 'J': 176228753Smm r = archive_write_set_compression_xz(a); 177228753Smm break; 178232153Smm case OPTION_LZIP: 179232153Smm r = archive_write_set_compression_lzip(a); 180232153Smm break; 181228753Smm case OPTION_LZMA: 182228753Smm r = archive_write_set_compression_lzma(a); 183228753Smm break; 184228753Smm case 'z': 185228753Smm r = archive_write_set_compression_gzip(a); 186228753Smm break; 187228753Smm case 'Z': 188228753Smm r = archive_write_set_compression_compress(a); 189228753Smm break; 190228753Smm default: 191228753Smm lafe_errc(1, 0, 192228753Smm "Unrecognized compression option -%c", 193228753Smm bsdtar->create_compression); 194228753Smm } 195228753Smm if (r != ARCHIVE_OK) { 196228753Smm lafe_errc(1, 0, 197228753Smm "Unsupported compression option -%c", 198228753Smm bsdtar->create_compression); 199228753Smm } 200228753Smm } 201228753Smm 202228753Smm if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) 203228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 204228753Smm if (ARCHIVE_OK != archive_write_open_file(a, bsdtar->filename)) 205228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 206228753Smm write_archive(a, bsdtar); 207228753Smm} 208228753Smm 209228753Smm/* 210228753Smm * Same as 'c', except we only support tar or empty formats in 211228753Smm * uncompressed files on disk. 212228753Smm */ 213228753Smmvoid 214228753Smmtar_mode_r(struct bsdtar *bsdtar) 215228753Smm{ 216228753Smm int64_t end_offset; 217228753Smm int format; 218228753Smm struct archive *a; 219228753Smm struct archive_entry *entry; 220228753Smm int r; 221228753Smm 222228753Smm /* Sanity-test some arguments and the file. */ 223228753Smm test_for_append(bsdtar); 224228753Smm 225228753Smm format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; 226228753Smm 227228753Smm#if defined(__BORLANDC__) 228228753Smm bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY); 229228753Smm#else 230228753Smm bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY, 0666); 231228753Smm#endif 232228753Smm if (bsdtar->fd < 0) 233228753Smm lafe_errc(1, errno, 234228753Smm "Cannot open %s", bsdtar->filename); 235228753Smm 236228753Smm a = archive_read_new(); 237232153Smm archive_read_support_filter_all(a); 238239622Smm archive_read_support_format_empty(a); 239228753Smm archive_read_support_format_tar(a); 240228753Smm archive_read_support_format_gnutar(a); 241228753Smm r = archive_read_open_fd(a, bsdtar->fd, 10240); 242228753Smm if (r != ARCHIVE_OK) 243228753Smm lafe_errc(1, archive_errno(a), 244228753Smm "Can't read archive %s: %s", bsdtar->filename, 245228753Smm archive_error_string(a)); 246228753Smm while (0 == archive_read_next_header(a, &entry)) { 247228753Smm if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) { 248232153Smm archive_read_free(a); 249228753Smm close(bsdtar->fd); 250228753Smm lafe_errc(1, 0, 251228753Smm "Cannot append to compressed archive."); 252228753Smm } 253228753Smm /* Keep going until we hit end-of-archive */ 254228753Smm format = archive_format(a); 255228753Smm } 256228753Smm 257228753Smm end_offset = archive_read_header_position(a); 258232153Smm archive_read_free(a); 259228753Smm 260228753Smm /* Re-open archive for writing */ 261228753Smm a = archive_write_new(); 262228753Smm /* 263228753Smm * Set the format to be used for writing. To allow people to 264228753Smm * extend empty files, we need to allow them to specify the format, 265228753Smm * which opens the possibility that they will specify a format that 266228753Smm * doesn't match the existing format. Hence, the following bit 267228753Smm * of arcane ugliness. 268228753Smm */ 269228753Smm 270228753Smm if (bsdtar->create_format != NULL) { 271228753Smm /* If the user requested a format, use that, but ... */ 272228753Smm archive_write_set_format_by_name(a, 273228753Smm bsdtar->create_format); 274228753Smm /* ... complain if it's not compatible. */ 275228753Smm format &= ARCHIVE_FORMAT_BASE_MASK; 276228753Smm if (format != (int)(archive_format(a) & ARCHIVE_FORMAT_BASE_MASK) 277228753Smm && format != ARCHIVE_FORMAT_EMPTY) { 278228753Smm lafe_errc(1, 0, 279228753Smm "Format %s is incompatible with the archive %s.", 280228753Smm bsdtar->create_format, bsdtar->filename); 281228753Smm } 282228753Smm } else { 283228753Smm /* 284228753Smm * Just preserve the current format, with a little care 285228753Smm * for formats that libarchive can't write. 286228753Smm */ 287228753Smm if (format == ARCHIVE_FORMAT_EMPTY) 288228753Smm format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; 289228753Smm archive_write_set_format(a, format); 290228753Smm } 291228753Smm if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0) 292228753Smm lafe_errc(1, errno, "Could not seek to archive end"); 293228753Smm if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) 294228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 295228753Smm if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd)) 296228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 297228753Smm 298228753Smm write_archive(a, bsdtar); /* XXX check return val XXX */ 299228753Smm 300228753Smm close(bsdtar->fd); 301228753Smm bsdtar->fd = -1; 302228753Smm} 303228753Smm 304228753Smmvoid 305228753Smmtar_mode_u(struct bsdtar *bsdtar) 306228753Smm{ 307228753Smm int64_t end_offset; 308228753Smm struct archive *a; 309228753Smm struct archive_entry *entry; 310228753Smm int format; 311228753Smm struct archive_dir_entry *p; 312228753Smm struct archive_dir archive_dir; 313228753Smm 314228753Smm bsdtar->archive_dir = &archive_dir; 315228753Smm memset(&archive_dir, 0, sizeof(archive_dir)); 316228753Smm 317228753Smm format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; 318228753Smm 319228753Smm /* Sanity-test some arguments and the file. */ 320228753Smm test_for_append(bsdtar); 321228753Smm 322228753Smm bsdtar->fd = open(bsdtar->filename, O_RDWR | O_BINARY); 323228753Smm if (bsdtar->fd < 0) 324228753Smm lafe_errc(1, errno, 325228753Smm "Cannot open %s", bsdtar->filename); 326228753Smm 327228753Smm a = archive_read_new(); 328232153Smm archive_read_support_filter_all(a); 329228753Smm archive_read_support_format_tar(a); 330228753Smm archive_read_support_format_gnutar(a); 331232153Smm if (archive_read_open_fd(a, bsdtar->fd, bsdtar->bytes_per_block) 332232153Smm != ARCHIVE_OK) { 333228753Smm lafe_errc(1, 0, 334228753Smm "Can't open %s: %s", bsdtar->filename, 335228753Smm archive_error_string(a)); 336228753Smm } 337228753Smm 338228753Smm /* Build a list of all entries and their recorded mod times. */ 339228753Smm while (0 == archive_read_next_header(a, &entry)) { 340228753Smm if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) { 341232153Smm archive_read_free(a); 342228753Smm close(bsdtar->fd); 343228753Smm lafe_errc(1, 0, 344228753Smm "Cannot append to compressed archive."); 345228753Smm } 346238856Smm if (archive_match_exclude_entry(bsdtar->matching, 347238856Smm ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER | 348238856Smm ARCHIVE_MATCH_EQUAL, entry) != ARCHIVE_OK) 349238856Smm lafe_errc(1, 0, "Error : %s", 350238856Smm archive_error_string(bsdtar->matching)); 351228753Smm /* Record the last format determination we see */ 352228753Smm format = archive_format(a); 353228753Smm /* Keep going until we hit end-of-archive */ 354228753Smm } 355228753Smm 356228753Smm end_offset = archive_read_header_position(a); 357232153Smm archive_read_free(a); 358228753Smm 359228753Smm /* Re-open archive for writing. */ 360228753Smm a = archive_write_new(); 361228753Smm /* 362232153Smm * Set format to same one auto-detected above. 363228753Smm */ 364228753Smm archive_write_set_format(a, format); 365232153Smm archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); 366232153Smm archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); 367232153Smm 368228753Smm if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0) 369228753Smm lafe_errc(1, errno, "Could not seek to archive end"); 370228753Smm if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) 371228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 372228753Smm if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd)) 373228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 374228753Smm 375228753Smm write_archive(a, bsdtar); 376228753Smm 377228753Smm close(bsdtar->fd); 378228753Smm bsdtar->fd = -1; 379228753Smm 380228753Smm while (bsdtar->archive_dir->head != NULL) { 381228753Smm p = bsdtar->archive_dir->head->next; 382228753Smm free(bsdtar->archive_dir->head->name); 383228753Smm free(bsdtar->archive_dir->head); 384228753Smm bsdtar->archive_dir->head = p; 385228753Smm } 386228753Smm bsdtar->archive_dir->tail = NULL; 387228753Smm} 388228753Smm 389228753Smm 390228753Smm/* 391228753Smm * Write user-specified files/dirs to opened archive. 392228753Smm */ 393228753Smmstatic void 394228753Smmwrite_archive(struct archive *a, struct bsdtar *bsdtar) 395228753Smm{ 396228753Smm const char *arg; 397228753Smm struct archive_entry *entry, *sparse_entry; 398228753Smm 399232153Smm /* Choose a suitable copy buffer size */ 400232153Smm bsdtar->buff_size = 64 * 1024; 401232153Smm while (bsdtar->buff_size < (size_t)bsdtar->bytes_per_block) 402232153Smm bsdtar->buff_size *= 2; 403232153Smm /* Try to compensate for space we'll lose to alignment. */ 404232153Smm bsdtar->buff_size += 16 * 1024; 405232153Smm 406228753Smm /* Allocate a buffer for file data. */ 407232153Smm if ((bsdtar->buff = malloc(bsdtar->buff_size)) == NULL) 408228753Smm lafe_errc(1, 0, "cannot allocate memory"); 409228753Smm 410228753Smm if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL) 411228753Smm lafe_errc(1, 0, "cannot create link resolver"); 412228753Smm archive_entry_linkresolver_set_strategy(bsdtar->resolver, 413228753Smm archive_format(a)); 414238856Smm 415238856Smm /* Create a read_disk object. */ 416228753Smm if ((bsdtar->diskreader = archive_read_disk_new()) == NULL) 417228753Smm lafe_errc(1, 0, "Cannot create read_disk object"); 418238856Smm /* Tell the read_disk how handle symlink. */ 419238856Smm switch (bsdtar->symlink_mode) { 420238856Smm case 'H': 421238856Smm archive_read_disk_set_symlink_hybrid(bsdtar->diskreader); 422238856Smm break; 423238856Smm case 'L': 424238856Smm archive_read_disk_set_symlink_logical(bsdtar->diskreader); 425238856Smm break; 426238856Smm default: 427238856Smm archive_read_disk_set_symlink_physical(bsdtar->diskreader); 428238856Smm break; 429238856Smm } 430238856Smm /* Register entry filters. */ 431238856Smm archive_read_disk_set_matching(bsdtar->diskreader, 432238856Smm bsdtar->matching, excluded_callback, bsdtar); 433238856Smm archive_read_disk_set_metadata_filter_callback( 434238856Smm bsdtar->diskreader, metadata_filter, bsdtar); 435238856Smm /* Set the behavior of archive_read_disk. */ 436238856Smm archive_read_disk_set_behavior(bsdtar->diskreader, 437238856Smm bsdtar->readdisk_flags); 438228753Smm archive_read_disk_set_standard_lookup(bsdtar->diskreader); 439228753Smm 440228753Smm if (bsdtar->names_from_file != NULL) 441228753Smm archive_names_from_file(bsdtar, a); 442228753Smm 443228753Smm while (*bsdtar->argv) { 444228753Smm arg = *bsdtar->argv; 445228753Smm if (arg[0] == '-' && arg[1] == 'C') { 446228753Smm arg += 2; 447228753Smm if (*arg == '\0') { 448228753Smm bsdtar->argv++; 449228753Smm arg = *bsdtar->argv; 450228753Smm if (arg == NULL) { 451228753Smm lafe_warnc(0, "%s", 452228753Smm "Missing argument for -C"); 453228753Smm bsdtar->return_value = 1; 454228753Smm goto cleanup; 455228753Smm } 456232153Smm if (*arg == '\0') { 457232153Smm lafe_warnc(0, 458232153Smm "Meaningless argument for -C: ''"); 459232153Smm bsdtar->return_value = 1; 460232153Smm goto cleanup; 461232153Smm } 462228753Smm } 463228753Smm set_chdir(bsdtar, arg); 464228753Smm } else { 465228753Smm if (*arg != '/' && (arg[0] != '@' || arg[1] != '/')) 466228753Smm do_chdir(bsdtar); /* Handle a deferred -C */ 467228753Smm if (*arg == '@') { 468228753Smm if (append_archive_filename(bsdtar, a, 469228753Smm arg + 1) != 0) 470228753Smm break; 471228753Smm } else 472228753Smm write_hierarchy(bsdtar, a, arg); 473228753Smm } 474228753Smm bsdtar->argv++; 475228753Smm } 476228753Smm 477238856Smm archive_read_disk_set_matching(bsdtar->diskreader, NULL, NULL, NULL); 478238856Smm archive_read_disk_set_metadata_filter_callback( 479238856Smm bsdtar->diskreader, NULL, NULL); 480228753Smm entry = NULL; 481228753Smm archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); 482228753Smm while (entry != NULL) { 483238856Smm int r; 484238856Smm struct archive_entry *entry2; 485238856Smm struct archive *disk = bsdtar->diskreader; 486238856Smm 487238856Smm /* 488238856Smm * This tricky code here is to correctly read the cotents 489238856Smm * of the entry because the disk reader bsdtar->diskreader 490238856Smm * is pointing at does not have any information about the 491238856Smm * entry by this time and using archive_read_data_block() 492238856Smm * with the disk reader consequently must fail. And we 493238856Smm * have to re-open the entry to read the contents. 494238856Smm */ 495238856Smm /* TODO: Work with -C option as well. */ 496238856Smm r = archive_read_disk_open(disk, 497238856Smm archive_entry_sourcepath(entry)); 498238856Smm if (r != ARCHIVE_OK) { 499238856Smm lafe_warnc(archive_errno(disk), 500238856Smm "%s", archive_error_string(disk)); 501238856Smm bsdtar->return_value = 1; 502238856Smm archive_entry_free(entry); 503238856Smm continue; 504238856Smm } 505238856Smm 506238856Smm /* 507238856Smm * Invoke archive_read_next_header2() to work 508238856Smm * archive_read_data_block(), which is called via write_file(), 509238856Smm * without failure. 510238856Smm */ 511238856Smm entry2 = archive_entry_new(); 512238856Smm r = archive_read_next_header2(disk, entry2); 513238856Smm archive_entry_free(entry2); 514238856Smm if (r != ARCHIVE_OK) { 515238856Smm lafe_warnc(archive_errno(disk), 516238856Smm "%s", archive_error_string(disk)); 517238856Smm if (r == ARCHIVE_FATAL) 518238856Smm bsdtar->return_value = 1; 519238856Smm else 520238856Smm archive_read_close(disk); 521238856Smm archive_entry_free(entry); 522238856Smm continue; 523238856Smm } 524238856Smm 525232153Smm write_file(bsdtar, a, entry); 526228753Smm archive_entry_free(entry); 527238856Smm archive_read_close(disk); 528228753Smm entry = NULL; 529228753Smm archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); 530228753Smm } 531228753Smm 532228753Smm if (archive_write_close(a)) { 533228753Smm lafe_warnc(0, "%s", archive_error_string(a)); 534228753Smm bsdtar->return_value = 1; 535228753Smm } 536228753Smm 537228753Smmcleanup: 538228753Smm /* Free file data buffer. */ 539228753Smm free(bsdtar->buff); 540228753Smm archive_entry_linkresolver_free(bsdtar->resolver); 541228753Smm bsdtar->resolver = NULL; 542232153Smm archive_read_free(bsdtar->diskreader); 543228753Smm bsdtar->diskreader = NULL; 544228753Smm 545228753Smm if (bsdtar->option_totals) { 546228753Smm fprintf(stderr, "Total bytes written: %s\n", 547228753Smm tar_i64toa(archive_position_compressed(a))); 548228753Smm } 549228753Smm 550232153Smm archive_write_free(a); 551228753Smm} 552228753Smm 553228753Smm/* 554228753Smm * Archive names specified in file. 555228753Smm * 556228753Smm * Unless --null was specified, a line containing exactly "-C" will 557228753Smm * cause the next line to be a directory to pass to chdir(). If 558228753Smm * --null is specified, then a line "-C" is just another filename. 559228753Smm */ 560228753Smmstatic void 561228753Smmarchive_names_from_file(struct bsdtar *bsdtar, struct archive *a) 562228753Smm{ 563228753Smm struct lafe_line_reader *lr; 564228753Smm const char *line; 565228753Smm 566228753Smm bsdtar->next_line_is_dir = 0; 567228753Smm 568228753Smm lr = lafe_line_reader(bsdtar->names_from_file, bsdtar->option_null); 569228753Smm while ((line = lafe_line_reader_next(lr)) != NULL) { 570228753Smm if (bsdtar->next_line_is_dir) { 571232153Smm if (*line != '\0') 572232153Smm set_chdir(bsdtar, line); 573232153Smm else { 574232153Smm lafe_warnc(0, 575232153Smm "Meaningless argument for -C: ''"); 576232153Smm bsdtar->return_value = 1; 577232153Smm } 578228753Smm bsdtar->next_line_is_dir = 0; 579228753Smm } else if (!bsdtar->option_null && strcmp(line, "-C") == 0) 580228753Smm bsdtar->next_line_is_dir = 1; 581228753Smm else { 582228753Smm if (*line != '/') 583228753Smm do_chdir(bsdtar); /* Handle a deferred -C */ 584228753Smm write_hierarchy(bsdtar, a, line); 585228753Smm } 586228753Smm } 587228753Smm lafe_line_reader_free(lr); 588228753Smm if (bsdtar->next_line_is_dir) 589228753Smm lafe_errc(1, errno, 590228753Smm "Unexpected end of filename list; " 591228753Smm "directory expected after -C"); 592228753Smm} 593228753Smm 594228753Smm/* 595228753Smm * Copy from specified archive to current archive. Returns non-zero 596228753Smm * for write errors (which force us to terminate the entire archiving 597228753Smm * operation). If there are errors reading the input archive, we set 598228753Smm * bsdtar->return_value but return zero, so the overall archiving 599228753Smm * operation will complete and return non-zero. 600228753Smm */ 601228753Smmstatic int 602228753Smmappend_archive_filename(struct bsdtar *bsdtar, struct archive *a, 603232153Smm const char *raw_filename) 604228753Smm{ 605228753Smm struct archive *ina; 606232153Smm const char *filename = raw_filename; 607228753Smm int rc; 608228753Smm 609228753Smm if (strcmp(filename, "-") == 0) 610228753Smm filename = NULL; /* Library uses NULL for stdio. */ 611228753Smm 612228753Smm ina = archive_read_new(); 613228753Smm archive_read_support_format_all(ina); 614232153Smm archive_read_support_filter_all(ina); 615232153Smm if (archive_read_open_file(ina, filename, bsdtar->bytes_per_block)) { 616228753Smm lafe_warnc(0, "%s", archive_error_string(ina)); 617228753Smm bsdtar->return_value = 1; 618228753Smm return (0); 619228753Smm } 620228753Smm 621228753Smm rc = append_archive(bsdtar, a, ina); 622228753Smm 623228753Smm if (rc != ARCHIVE_OK) { 624228753Smm lafe_warnc(0, "Error reading archive %s: %s", 625232153Smm raw_filename, archive_error_string(ina)); 626228753Smm bsdtar->return_value = 1; 627228753Smm } 628232153Smm archive_read_free(ina); 629228753Smm 630228753Smm return (rc); 631228753Smm} 632228753Smm 633228753Smmstatic int 634228753Smmappend_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) 635228753Smm{ 636228753Smm struct archive_entry *in_entry; 637228753Smm int e; 638228753Smm 639228753Smm while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) { 640238856Smm if (archive_match_excluded(bsdtar->matching, in_entry)) 641228753Smm continue; 642228753Smm if (bsdtar->option_interactive && 643228753Smm !yes("copy '%s'", archive_entry_pathname(in_entry))) 644228753Smm continue; 645228753Smm if (bsdtar->verbose) 646228753Smm safe_fprintf(stderr, "a %s", 647228753Smm archive_entry_pathname(in_entry)); 648228753Smm if (need_report()) 649228753Smm report_write(bsdtar, a, in_entry, 0); 650228753Smm 651228753Smm e = archive_write_header(a, in_entry); 652228753Smm if (e != ARCHIVE_OK) { 653228753Smm if (!bsdtar->verbose) 654228753Smm lafe_warnc(0, "%s: %s", 655228753Smm archive_entry_pathname(in_entry), 656228753Smm archive_error_string(a)); 657228753Smm else 658228753Smm fprintf(stderr, ": %s", archive_error_string(a)); 659228753Smm } 660228753Smm if (e == ARCHIVE_FATAL) 661228753Smm exit(1); 662228753Smm 663228753Smm if (e >= ARCHIVE_WARN) { 664228753Smm if (archive_entry_size(in_entry) == 0) 665228753Smm archive_read_data_skip(ina); 666238856Smm else if (copy_file_data_block(bsdtar, a, ina, in_entry)) 667228753Smm exit(1); 668228753Smm } 669228753Smm 670228753Smm if (bsdtar->verbose) 671228753Smm fprintf(stderr, "\n"); 672228753Smm } 673228753Smm 674228753Smm return (e == ARCHIVE_EOF ? ARCHIVE_OK : e); 675228753Smm} 676228753Smm 677238856Smm/* Helper function to copy file to archive. */ 678228753Smmstatic int 679238856Smmcopy_file_data_block(struct bsdtar *bsdtar, struct archive *a, 680238856Smm struct archive *in_a, struct archive_entry *entry) 681228753Smm{ 682238856Smm size_t bytes_read; 683228753Smm ssize_t bytes_written; 684238856Smm int64_t offset, progress = 0; 685238856Smm char *null_buff = NULL; 686238856Smm const void *buff; 687238856Smm int r; 688228753Smm 689238856Smm while ((r = archive_read_data_block(in_a, &buff, 690238856Smm &bytes_read, &offset)) == ARCHIVE_OK) { 691228753Smm if (need_report()) 692228753Smm report_write(bsdtar, a, entry, progress); 693228753Smm 694238856Smm if (offset > progress) { 695238856Smm int64_t sparse = offset - progress; 696238856Smm size_t ns; 697238856Smm 698238856Smm if (null_buff == NULL) { 699238856Smm null_buff = bsdtar->buff; 700238856Smm memset(null_buff, 0, bsdtar->buff_size); 701238856Smm } 702238856Smm 703238856Smm while (sparse > 0) { 704238856Smm if (sparse > (int64_t)bsdtar->buff_size) 705238856Smm ns = bsdtar->buff_size; 706238856Smm else 707238856Smm ns = (size_t)sparse; 708238856Smm bytes_written = 709238856Smm archive_write_data(a, null_buff, ns); 710238856Smm if (bytes_written < 0) { 711238856Smm /* Write failed; this is bad */ 712238856Smm lafe_warnc(0, "%s", 713238856Smm archive_error_string(a)); 714238856Smm return (-1); 715238856Smm } 716238856Smm if ((size_t)bytes_written < ns) { 717238856Smm /* Write was truncated; warn but 718238856Smm * continue. */ 719238856Smm lafe_warnc(0, 720238856Smm "%s: Truncated write; file may " 721238856Smm "have grown while being archived.", 722238856Smm archive_entry_pathname(entry)); 723238856Smm return (0); 724238856Smm } 725238856Smm progress += bytes_written; 726238856Smm sparse -= bytes_written; 727238856Smm } 728238856Smm } 729238856Smm 730238856Smm bytes_written = archive_write_data(a, buff, bytes_read); 731238856Smm if (bytes_written < 0) { 732238856Smm /* Write failed; this is bad */ 733228753Smm lafe_warnc(0, "%s", archive_error_string(a)); 734228753Smm return (-1); 735228753Smm } 736238856Smm if ((size_t)bytes_written < bytes_read) { 737238856Smm /* Write was truncated; warn but continue. */ 738238856Smm lafe_warnc(0, 739238856Smm "%s: Truncated write; file may have grown " 740238856Smm "while being archived.", 741238856Smm archive_entry_pathname(entry)); 742238856Smm return (0); 743238856Smm } 744228753Smm progress += bytes_written; 745228753Smm } 746238856Smm if (r < ARCHIVE_WARN) { 747238856Smm lafe_warnc(archive_errno(a), "%s", archive_error_string(a)); 748238856Smm return (-1); 749238856Smm } 750228753Smm return (0); 751228753Smm} 752228753Smm 753238856Smmstatic void 754238856Smmexcluded_callback(struct archive *a, void *_data, struct archive_entry *entry) 755238856Smm{ 756238856Smm struct bsdtar *bsdtar = (struct bsdtar *)_data; 757238856Smm 758238856Smm if (bsdtar->option_no_subdirs) 759238856Smm return; 760238856Smm if (!archive_read_disk_can_descend(a)) 761238856Smm return; 762238856Smm if (bsdtar->option_interactive && 763238856Smm !yes("add '%s'", archive_entry_pathname(entry))) 764238856Smm return; 765238856Smm archive_read_disk_descend(a); 766238856Smm} 767238856Smm 768238856Smmstatic int 769238856Smmmetadata_filter(struct archive *a, void *_data, struct archive_entry *entry) 770238856Smm{ 771238856Smm struct bsdtar *bsdtar = (struct bsdtar *)_data; 772238856Smm 773238856Smm /* XXX TODO: check whether this filesystem is 774238856Smm * synthetic and/or local. Add a new 775238856Smm * --local-only option to skip non-local 776238856Smm * filesystems. Skip synthetic filesystems 777238856Smm * regardless. 778238856Smm * 779238856Smm * The results should be cached, since 780238856Smm * tree.c doesn't usually visit a directory 781238856Smm * and the directory contents together. A simple 782238856Smm * move-to-front list should perform quite well. 783238856Smm * 784238856Smm * Use archive_read_disk_current_filesystem_is_remote(). 785238856Smm */ 786238856Smm 787238856Smm /* 788238856Smm * If the user vetoes this file/directory, skip it. 789238856Smm * We want this to be fairly late; if some other 790238856Smm * check would veto this file, we shouldn't bother 791238856Smm * the user with it. 792238856Smm */ 793238856Smm if (bsdtar->option_interactive && 794238856Smm !yes("add '%s'", archive_entry_pathname(entry))) 795238856Smm return (0); 796238856Smm 797238856Smm /* Note: if user vetoes, we won't descend. */ 798238856Smm if (!bsdtar->option_no_subdirs && archive_read_disk_can_descend(a)) 799238856Smm archive_read_disk_descend(a); 800238856Smm 801238856Smm return (1); 802238856Smm} 803238856Smm 804228753Smm/* 805228753Smm * Add the file or dir hierarchy named by 'path' to the archive 806228753Smm */ 807228753Smmstatic void 808228753Smmwrite_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) 809228753Smm{ 810238856Smm struct archive *disk = bsdtar->diskreader; 811228753Smm struct archive_entry *entry = NULL, *spare_entry = NULL; 812238856Smm int r; 813228753Smm 814238856Smm r = archive_read_disk_open(disk, path); 815238856Smm if (r != ARCHIVE_OK) { 816238856Smm lafe_warnc(archive_errno(disk), 817238856Smm "%s", archive_error_string(disk)); 818228753Smm bsdtar->return_value = 1; 819228753Smm return; 820228753Smm } 821238856Smm bsdtar->first_fs = -1; 822228753Smm 823238856Smm for (;;) { 824238856Smm archive_entry_free(entry); 825238856Smm entry = archive_entry_new(); 826238856Smm r = archive_read_next_header2(disk, entry); 827238856Smm if (r == ARCHIVE_EOF) 828228753Smm break; 829238856Smm else if (r != ARCHIVE_OK) { 830238856Smm lafe_warnc(archive_errno(disk), 831238856Smm "%s", archive_error_string(disk)); 832238856Smm if (r == ARCHIVE_FATAL) { 833238856Smm bsdtar->return_value = 1; 834238856Smm return; 835238856Smm } else if (r < ARCHIVE_WARN) 836228776Smm continue; 837228776Smm } 838228753Smm 839228753Smm if (bsdtar->uid >= 0) { 840228753Smm archive_entry_set_uid(entry, bsdtar->uid); 841228753Smm if (!bsdtar->uname) 842228753Smm archive_entry_set_uname(entry, 843228753Smm archive_read_disk_uname(bsdtar->diskreader, 844228753Smm bsdtar->uid)); 845228753Smm } 846228753Smm if (bsdtar->gid >= 0) { 847228753Smm archive_entry_set_gid(entry, bsdtar->gid); 848228753Smm if (!bsdtar->gname) 849228753Smm archive_entry_set_gname(entry, 850228753Smm archive_read_disk_gname(bsdtar->diskreader, 851228753Smm bsdtar->gid)); 852228753Smm } 853228753Smm if (bsdtar->uname) 854228753Smm archive_entry_set_uname(entry, bsdtar->uname); 855228753Smm if (bsdtar->gname) 856228753Smm archive_entry_set_gname(entry, bsdtar->gname); 857228753Smm 858228753Smm /* 859228753Smm * Rewrite the pathname to be archived. If rewrite 860228753Smm * fails, skip the entry. 861228753Smm */ 862228753Smm if (edit_pathname(bsdtar, entry)) 863228753Smm continue; 864228753Smm 865228753Smm /* Display entry as we process it. 866228753Smm * This format is required by SUSv2. */ 867228753Smm if (bsdtar->verbose) 868228753Smm safe_fprintf(stderr, "a %s", 869228753Smm archive_entry_pathname(entry)); 870228753Smm 871228753Smm /* Non-regular files get archived with zero size. */ 872228753Smm if (archive_entry_filetype(entry) != AE_IFREG) 873228753Smm archive_entry_set_size(entry, 0); 874228753Smm 875228753Smm archive_entry_linkify(bsdtar->resolver, &entry, &spare_entry); 876228753Smm 877228753Smm while (entry != NULL) { 878232153Smm write_file(bsdtar, a, entry); 879228753Smm archive_entry_free(entry); 880228753Smm entry = spare_entry; 881228753Smm spare_entry = NULL; 882228753Smm } 883228753Smm 884228753Smm if (bsdtar->verbose) 885228753Smm fprintf(stderr, "\n"); 886228753Smm } 887228753Smm archive_entry_free(entry); 888238856Smm archive_read_close(disk); 889228753Smm} 890228753Smm 891228753Smm/* 892232153Smm * Write a single file (or directory or other filesystem object) to 893232153Smm * the archive. 894228753Smm */ 895228753Smmstatic void 896232153Smmwrite_file(struct bsdtar *bsdtar, struct archive *a, 897228753Smm struct archive_entry *entry) 898228753Smm{ 899232153Smm write_entry(bsdtar, a, entry); 900232153Smm} 901232153Smm 902232153Smm/* 903232153Smm * Write a single entry to the archive. 904232153Smm */ 905232153Smmstatic void 906232153Smmwrite_entry(struct bsdtar *bsdtar, struct archive *a, 907232153Smm struct archive_entry *entry) 908232153Smm{ 909228753Smm int e; 910228753Smm 911228753Smm e = archive_write_header(a, entry); 912228753Smm if (e != ARCHIVE_OK) { 913228753Smm if (!bsdtar->verbose) 914228753Smm lafe_warnc(0, "%s: %s", 915228753Smm archive_entry_pathname(entry), 916228753Smm archive_error_string(a)); 917228753Smm else 918228753Smm fprintf(stderr, ": %s", archive_error_string(a)); 919228753Smm } 920228753Smm 921228753Smm if (e == ARCHIVE_FATAL) 922228753Smm exit(1); 923228753Smm 924228753Smm /* 925228753Smm * If we opened a file earlier, write it out now. Note that 926228753Smm * the format handler might have reset the size field to zero 927228753Smm * to inform us that the archive body won't get stored. In 928228753Smm * that case, just skip the write. 929228753Smm */ 930238856Smm if (e >= ARCHIVE_WARN && archive_entry_size(entry) > 0) { 931238856Smm if (copy_file_data_block(bsdtar, a, bsdtar->diskreader, entry)) 932228753Smm exit(1); 933228753Smm } 934228753Smm} 935228753Smm 936228753Smmstatic void 937228753Smmreport_write(struct bsdtar *bsdtar, struct archive *a, 938228753Smm struct archive_entry *entry, int64_t progress) 939228753Smm{ 940228753Smm uint64_t comp, uncomp; 941228776Smm int compression; 942228776Smm 943228753Smm if (bsdtar->verbose) 944228753Smm fprintf(stderr, "\n"); 945228753Smm comp = archive_position_compressed(a); 946228753Smm uncomp = archive_position_uncompressed(a); 947228753Smm fprintf(stderr, "In: %d files, %s bytes;", 948228753Smm archive_file_count(a), tar_i64toa(uncomp)); 949228776Smm if (comp > uncomp) 950228776Smm compression = 0; 951228776Smm else 952228776Smm compression = (int)((uncomp - comp) * 100 / uncomp); 953228753Smm fprintf(stderr, 954228753Smm " Out: %s bytes, compression %d%%\n", 955228776Smm tar_i64toa(comp), compression); 956228753Smm /* Can't have two calls to tar_i64toa() pending, so split the output. */ 957228753Smm safe_fprintf(stderr, "Current: %s (%s", 958228753Smm archive_entry_pathname(entry), 959228753Smm tar_i64toa(progress)); 960228753Smm fprintf(stderr, "/%s bytes)\n", 961228753Smm tar_i64toa(archive_entry_size(entry))); 962228753Smm} 963228753Smm 964228753Smmstatic void 965228753Smmtest_for_append(struct bsdtar *bsdtar) 966228753Smm{ 967228753Smm struct stat s; 968228753Smm 969228753Smm if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) 970228753Smm lafe_errc(1, 0, "no files or directories specified"); 971228753Smm if (bsdtar->filename == NULL) 972228753Smm lafe_errc(1, 0, "Cannot append to stdout."); 973228753Smm 974228753Smm if (bsdtar->create_compression != 0) 975228753Smm lafe_errc(1, 0, 976228753Smm "Cannot append to %s with compression", bsdtar->filename); 977228753Smm 978228753Smm if (stat(bsdtar->filename, &s) != 0) 979228753Smm return; 980228753Smm 981228753Smm if (!S_ISREG(s.st_mode) && !S_ISBLK(s.st_mode)) 982228753Smm lafe_errc(1, 0, 983228753Smm "Cannot append to %s: not a regular file.", 984228753Smm bsdtar->filename); 985228753Smm 986228753Smm/* Is this an appropriate check here on Windows? */ 987228753Smm/* 988228753Smm if (GetFileType(handle) != FILE_TYPE_DISK) 989228753Smm lafe_errc(1, 0, "Cannot append"); 990228753Smm*/ 991228753Smm 992228753Smm} 993