1caf54c4fSMartin Matuska /*- 2caf54c4fSMartin Matuska * Copyright (c) 2003-2007 Tim Kientzle 3caf54c4fSMartin Matuska * All rights reserved. 4caf54c4fSMartin Matuska * 5caf54c4fSMartin Matuska * Redistribution and use in source and binary forms, with or without 6caf54c4fSMartin Matuska * modification, are permitted provided that the following conditions 7caf54c4fSMartin Matuska * are met: 8caf54c4fSMartin Matuska * 1. Redistributions of source code must retain the above copyright 9caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer. 10caf54c4fSMartin Matuska * 2. Redistributions in binary form must reproduce the above copyright 11caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer in the 12caf54c4fSMartin Matuska * documentation and/or other materials provided with the distribution. 13caf54c4fSMartin Matuska * 14caf54c4fSMartin Matuska * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15caf54c4fSMartin Matuska * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16caf54c4fSMartin Matuska * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17caf54c4fSMartin Matuska * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18caf54c4fSMartin Matuska * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19caf54c4fSMartin Matuska * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20caf54c4fSMartin Matuska * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21caf54c4fSMartin Matuska * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22caf54c4fSMartin Matuska * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23caf54c4fSMartin Matuska * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24caf54c4fSMartin Matuska */ 25caf54c4fSMartin Matuska 26caf54c4fSMartin Matuska #include "bsdtar_platform.h" 276c22d9efSMartin Matuska __FBSDID("$FreeBSD$"); 28caf54c4fSMartin Matuska 29caf54c4fSMartin Matuska #ifdef HAVE_SYS_TYPES_H 30caf54c4fSMartin Matuska #include <sys/types.h> 31caf54c4fSMartin Matuska #endif 32caf54c4fSMartin Matuska #ifdef HAVE_SYS_IOCTL_H 33caf54c4fSMartin Matuska #include <sys/ioctl.h> 34caf54c4fSMartin Matuska #endif 35caf54c4fSMartin Matuska #ifdef HAVE_SYS_STAT_H 36caf54c4fSMartin Matuska #include <sys/stat.h> 37caf54c4fSMartin Matuska #endif 38caf54c4fSMartin Matuska #ifdef HAVE_ATTR_XATTR_H 39caf54c4fSMartin Matuska #include <attr/xattr.h> 40caf54c4fSMartin Matuska #endif 41caf54c4fSMartin Matuska #ifdef HAVE_ERRNO_H 42caf54c4fSMartin Matuska #include <errno.h> 43caf54c4fSMartin Matuska #endif 44caf54c4fSMartin Matuska #ifdef HAVE_FCNTL_H 45caf54c4fSMartin Matuska #include <fcntl.h> 46caf54c4fSMartin Matuska #endif 47caf54c4fSMartin Matuska #ifdef HAVE_GRP_H 48caf54c4fSMartin Matuska #include <grp.h> 49caf54c4fSMartin Matuska #endif 50caf54c4fSMartin Matuska #ifdef HAVE_IO_H 51caf54c4fSMartin Matuska #include <io.h> 52caf54c4fSMartin Matuska #endif 53*6c95142eSMartin Matuska #ifdef HAVE_LIBGEN_H 54*6c95142eSMartin Matuska #include <libgen.h> 55*6c95142eSMartin Matuska #endif 56caf54c4fSMartin Matuska #ifdef HAVE_LIMITS_H 57caf54c4fSMartin Matuska #include <limits.h> 58caf54c4fSMartin Matuska #endif 59caf54c4fSMartin Matuska #ifdef HAVE_LINUX_FS_H 60caf54c4fSMartin Matuska #include <linux/fs.h> /* for Linux file flags */ 61caf54c4fSMartin Matuska #endif 62caf54c4fSMartin Matuska /* 63caf54c4fSMartin Matuska * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 64caf54c4fSMartin Matuska * As the include guards don't agree, the order of include is important. 65caf54c4fSMartin Matuska */ 66caf54c4fSMartin Matuska #ifdef HAVE_LINUX_EXT2_FS_H 67caf54c4fSMartin Matuska #include <linux/ext2_fs.h> /* for Linux file flags */ 68caf54c4fSMartin Matuska #endif 69caf54c4fSMartin Matuska #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 70caf54c4fSMartin Matuska /* This header exists but is broken on Cygwin. */ 71caf54c4fSMartin Matuska #include <ext2fs/ext2_fs.h> 72caf54c4fSMartin Matuska #endif 73*6c95142eSMartin Matuska #ifdef HAVE_PATHS_H 74*6c95142eSMartin Matuska #include <paths.h> 75*6c95142eSMartin Matuska #endif 76caf54c4fSMartin Matuska #ifdef HAVE_PWD_H 77caf54c4fSMartin Matuska #include <pwd.h> 78caf54c4fSMartin Matuska #endif 79caf54c4fSMartin Matuska #ifdef HAVE_STDINT_H 80caf54c4fSMartin Matuska #include <stdint.h> 81caf54c4fSMartin Matuska #endif 82caf54c4fSMartin Matuska #include <stdio.h> 83caf54c4fSMartin Matuska #ifdef HAVE_STDLIB_H 84caf54c4fSMartin Matuska #include <stdlib.h> 85caf54c4fSMartin Matuska #endif 86caf54c4fSMartin Matuska #ifdef HAVE_STRING_H 87caf54c4fSMartin Matuska #include <string.h> 88caf54c4fSMartin Matuska #endif 89caf54c4fSMartin Matuska #ifdef HAVE_UNISTD_H 90caf54c4fSMartin Matuska #include <unistd.h> 91caf54c4fSMartin Matuska #endif 92caf54c4fSMartin Matuska 93caf54c4fSMartin Matuska #include "bsdtar.h" 94caf54c4fSMartin Matuska #include "err.h" 95caf54c4fSMartin Matuska #include "line_reader.h" 96caf54c4fSMartin Matuska #include "tree.h" 97caf54c4fSMartin Matuska 98caf54c4fSMartin Matuska #ifndef O_BINARY 99caf54c4fSMartin Matuska #define O_BINARY 0 100caf54c4fSMartin Matuska #endif 101caf54c4fSMartin Matuska 102caf54c4fSMartin Matuska struct archive_dir_entry { 103caf54c4fSMartin Matuska struct archive_dir_entry *next; 104caf54c4fSMartin Matuska time_t mtime_sec; 105caf54c4fSMartin Matuska int mtime_nsec; 106caf54c4fSMartin Matuska char *name; 107caf54c4fSMartin Matuska }; 108caf54c4fSMartin Matuska 109caf54c4fSMartin Matuska struct archive_dir { 110caf54c4fSMartin Matuska struct archive_dir_entry *head, *tail; 111caf54c4fSMartin Matuska }; 112caf54c4fSMartin Matuska 113caf54c4fSMartin Matuska static void add_dir_list(struct bsdtar *bsdtar, const char *path, 114caf54c4fSMartin Matuska time_t mtime_sec, int mtime_nsec); 115caf54c4fSMartin Matuska static int append_archive(struct bsdtar *, struct archive *, 116caf54c4fSMartin Matuska struct archive *ina); 117caf54c4fSMartin Matuska static int append_archive_filename(struct bsdtar *, 118caf54c4fSMartin Matuska struct archive *, const char *fname); 119caf54c4fSMartin Matuska static void archive_names_from_file(struct bsdtar *bsdtar, 120caf54c4fSMartin Matuska struct archive *a); 121caf54c4fSMartin Matuska static int copy_file_data(struct bsdtar *, struct archive *a, 122caf54c4fSMartin Matuska struct archive *ina, struct archive_entry *); 123caf54c4fSMartin Matuska static int new_enough(struct bsdtar *, const char *path, 124caf54c4fSMartin Matuska const struct stat *); 125caf54c4fSMartin Matuska static void report_write(struct bsdtar *, struct archive *, 126caf54c4fSMartin Matuska struct archive_entry *, int64_t progress); 127caf54c4fSMartin Matuska static void test_for_append(struct bsdtar *); 128caf54c4fSMartin Matuska static void write_archive(struct archive *, struct bsdtar *); 129*6c95142eSMartin Matuska static void write_entry(struct bsdtar *, struct archive *, 130*6c95142eSMartin Matuska struct archive_entry *); 131*6c95142eSMartin Matuska static void write_file(struct bsdtar *, struct archive *, 132caf54c4fSMartin Matuska struct archive_entry *); 133caf54c4fSMartin Matuska static int write_file_data(struct bsdtar *, struct archive *, 134*6c95142eSMartin Matuska struct archive_entry *, int fd, size_t align); 135caf54c4fSMartin Matuska static void write_hierarchy(struct bsdtar *, struct archive *, 136caf54c4fSMartin Matuska const char *); 137caf54c4fSMartin Matuska 138caf54c4fSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 139caf54c4fSMartin Matuska /* Not a full lseek() emulation, but enough for our needs here. */ 140caf54c4fSMartin Matuska static int 141caf54c4fSMartin Matuska seek_file(int fd, int64_t offset, int whence) 142caf54c4fSMartin Matuska { 143caf54c4fSMartin Matuska LARGE_INTEGER distance; 144caf54c4fSMartin Matuska (void)whence; /* UNUSED */ 145caf54c4fSMartin Matuska distance.QuadPart = offset; 146caf54c4fSMartin Matuska return (SetFilePointerEx((HANDLE)_get_osfhandle(fd), 147caf54c4fSMartin Matuska distance, NULL, FILE_BEGIN) ? 1 : -1); 148caf54c4fSMartin Matuska } 149caf54c4fSMartin Matuska #define open _open 150caf54c4fSMartin Matuska #define close _close 151caf54c4fSMartin Matuska #define read _read 152caf54c4fSMartin Matuska #define lseek seek_file 153caf54c4fSMartin Matuska #endif 154caf54c4fSMartin Matuska 155caf54c4fSMartin Matuska void 156caf54c4fSMartin Matuska tar_mode_c(struct bsdtar *bsdtar) 157caf54c4fSMartin Matuska { 158caf54c4fSMartin Matuska struct archive *a; 159caf54c4fSMartin Matuska int r; 160caf54c4fSMartin Matuska 161caf54c4fSMartin Matuska if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) 162caf54c4fSMartin Matuska lafe_errc(1, 0, "no files or directories specified"); 163caf54c4fSMartin Matuska 164caf54c4fSMartin Matuska a = archive_write_new(); 165caf54c4fSMartin Matuska 166caf54c4fSMartin Matuska /* Support any format that the library supports. */ 167caf54c4fSMartin Matuska if (bsdtar->create_format == NULL) { 168caf54c4fSMartin Matuska r = archive_write_set_format_pax_restricted(a); 169caf54c4fSMartin Matuska bsdtar->create_format = "pax restricted"; 170caf54c4fSMartin Matuska } else { 171caf54c4fSMartin Matuska r = archive_write_set_format_by_name(a, bsdtar->create_format); 172caf54c4fSMartin Matuska } 173caf54c4fSMartin Matuska if (r != ARCHIVE_OK) { 174caf54c4fSMartin Matuska fprintf(stderr, "Can't use format %s: %s\n", 175caf54c4fSMartin Matuska bsdtar->create_format, 176caf54c4fSMartin Matuska archive_error_string(a)); 177caf54c4fSMartin Matuska usage(); 178caf54c4fSMartin Matuska } 179caf54c4fSMartin Matuska 180caf54c4fSMartin Matuska archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); 181*6c95142eSMartin Matuska archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); 182caf54c4fSMartin Matuska 183caf54c4fSMartin Matuska if (bsdtar->compress_program) { 184caf54c4fSMartin Matuska archive_write_set_compression_program(a, bsdtar->compress_program); 185caf54c4fSMartin Matuska } else { 186caf54c4fSMartin Matuska switch (bsdtar->create_compression) { 187caf54c4fSMartin Matuska case 0: 188*6c95142eSMartin Matuska r = ARCHIVE_OK; 189caf54c4fSMartin Matuska break; 190caf54c4fSMartin Matuska case 'j': case 'y': 191caf54c4fSMartin Matuska r = archive_write_set_compression_bzip2(a); 192caf54c4fSMartin Matuska break; 193caf54c4fSMartin Matuska case 'J': 194caf54c4fSMartin Matuska r = archive_write_set_compression_xz(a); 195caf54c4fSMartin Matuska break; 196*6c95142eSMartin Matuska case OPTION_LZIP: 197*6c95142eSMartin Matuska r = archive_write_set_compression_lzip(a); 198*6c95142eSMartin Matuska break; 199caf54c4fSMartin Matuska case OPTION_LZMA: 200caf54c4fSMartin Matuska r = archive_write_set_compression_lzma(a); 201caf54c4fSMartin Matuska break; 202caf54c4fSMartin Matuska case 'z': 203caf54c4fSMartin Matuska r = archive_write_set_compression_gzip(a); 204caf54c4fSMartin Matuska break; 205caf54c4fSMartin Matuska case 'Z': 206caf54c4fSMartin Matuska r = archive_write_set_compression_compress(a); 207caf54c4fSMartin Matuska break; 208caf54c4fSMartin Matuska default: 209caf54c4fSMartin Matuska lafe_errc(1, 0, 210caf54c4fSMartin Matuska "Unrecognized compression option -%c", 211caf54c4fSMartin Matuska bsdtar->create_compression); 212caf54c4fSMartin Matuska } 213caf54c4fSMartin Matuska if (r != ARCHIVE_OK) { 214caf54c4fSMartin Matuska lafe_errc(1, 0, 215caf54c4fSMartin Matuska "Unsupported compression option -%c", 216caf54c4fSMartin Matuska bsdtar->create_compression); 217caf54c4fSMartin Matuska } 218caf54c4fSMartin Matuska } 219caf54c4fSMartin Matuska 220caf54c4fSMartin Matuska if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) 221caf54c4fSMartin Matuska lafe_errc(1, 0, "%s", archive_error_string(a)); 222caf54c4fSMartin Matuska if (ARCHIVE_OK != archive_write_open_file(a, bsdtar->filename)) 223caf54c4fSMartin Matuska lafe_errc(1, 0, "%s", archive_error_string(a)); 224caf54c4fSMartin Matuska write_archive(a, bsdtar); 225caf54c4fSMartin Matuska } 226caf54c4fSMartin Matuska 227caf54c4fSMartin Matuska /* 228caf54c4fSMartin Matuska * Same as 'c', except we only support tar or empty formats in 229caf54c4fSMartin Matuska * uncompressed files on disk. 230caf54c4fSMartin Matuska */ 231caf54c4fSMartin Matuska void 232caf54c4fSMartin Matuska tar_mode_r(struct bsdtar *bsdtar) 233caf54c4fSMartin Matuska { 234caf54c4fSMartin Matuska int64_t end_offset; 235caf54c4fSMartin Matuska int format; 236caf54c4fSMartin Matuska struct archive *a; 237caf54c4fSMartin Matuska struct archive_entry *entry; 238caf54c4fSMartin Matuska int r; 239caf54c4fSMartin Matuska 240caf54c4fSMartin Matuska /* Sanity-test some arguments and the file. */ 241caf54c4fSMartin Matuska test_for_append(bsdtar); 242caf54c4fSMartin Matuska 243caf54c4fSMartin Matuska format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; 244caf54c4fSMartin Matuska 245caf54c4fSMartin Matuska #if defined(__BORLANDC__) 246caf54c4fSMartin Matuska bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY); 247caf54c4fSMartin Matuska #else 248caf54c4fSMartin Matuska bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY, 0666); 249caf54c4fSMartin Matuska #endif 250caf54c4fSMartin Matuska if (bsdtar->fd < 0) 251caf54c4fSMartin Matuska lafe_errc(1, errno, 252caf54c4fSMartin Matuska "Cannot open %s", bsdtar->filename); 253caf54c4fSMartin Matuska 254caf54c4fSMartin Matuska a = archive_read_new(); 255*6c95142eSMartin Matuska archive_read_support_filter_all(a); 256caf54c4fSMartin Matuska archive_read_support_format_tar(a); 257caf54c4fSMartin Matuska archive_read_support_format_gnutar(a); 258caf54c4fSMartin Matuska r = archive_read_open_fd(a, bsdtar->fd, 10240); 259caf54c4fSMartin Matuska if (r != ARCHIVE_OK) 260caf54c4fSMartin Matuska lafe_errc(1, archive_errno(a), 261caf54c4fSMartin Matuska "Can't read archive %s: %s", bsdtar->filename, 262caf54c4fSMartin Matuska archive_error_string(a)); 263caf54c4fSMartin Matuska while (0 == archive_read_next_header(a, &entry)) { 264caf54c4fSMartin Matuska if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) { 265*6c95142eSMartin Matuska archive_read_free(a); 266caf54c4fSMartin Matuska close(bsdtar->fd); 267caf54c4fSMartin Matuska lafe_errc(1, 0, 268caf54c4fSMartin Matuska "Cannot append to compressed archive."); 269caf54c4fSMartin Matuska } 270caf54c4fSMartin Matuska /* Keep going until we hit end-of-archive */ 271caf54c4fSMartin Matuska format = archive_format(a); 272caf54c4fSMartin Matuska } 273caf54c4fSMartin Matuska 274caf54c4fSMartin Matuska end_offset = archive_read_header_position(a); 275*6c95142eSMartin Matuska archive_read_free(a); 276caf54c4fSMartin Matuska 277caf54c4fSMartin Matuska /* Re-open archive for writing */ 278caf54c4fSMartin Matuska a = archive_write_new(); 279caf54c4fSMartin Matuska /* 280caf54c4fSMartin Matuska * Set the format to be used for writing. To allow people to 281caf54c4fSMartin Matuska * extend empty files, we need to allow them to specify the format, 282caf54c4fSMartin Matuska * which opens the possibility that they will specify a format that 283caf54c4fSMartin Matuska * doesn't match the existing format. Hence, the following bit 284caf54c4fSMartin Matuska * of arcane ugliness. 285caf54c4fSMartin Matuska */ 286caf54c4fSMartin Matuska 287caf54c4fSMartin Matuska if (bsdtar->create_format != NULL) { 288caf54c4fSMartin Matuska /* If the user requested a format, use that, but ... */ 289caf54c4fSMartin Matuska archive_write_set_format_by_name(a, 290caf54c4fSMartin Matuska bsdtar->create_format); 291caf54c4fSMartin Matuska /* ... complain if it's not compatible. */ 292caf54c4fSMartin Matuska format &= ARCHIVE_FORMAT_BASE_MASK; 293caf54c4fSMartin Matuska if (format != (int)(archive_format(a) & ARCHIVE_FORMAT_BASE_MASK) 294caf54c4fSMartin Matuska && format != ARCHIVE_FORMAT_EMPTY) { 295caf54c4fSMartin Matuska lafe_errc(1, 0, 296caf54c4fSMartin Matuska "Format %s is incompatible with the archive %s.", 297caf54c4fSMartin Matuska bsdtar->create_format, bsdtar->filename); 298caf54c4fSMartin Matuska } 299caf54c4fSMartin Matuska } else { 300caf54c4fSMartin Matuska /* 301caf54c4fSMartin Matuska * Just preserve the current format, with a little care 302caf54c4fSMartin Matuska * for formats that libarchive can't write. 303caf54c4fSMartin Matuska */ 304caf54c4fSMartin Matuska if (format == ARCHIVE_FORMAT_EMPTY) 305caf54c4fSMartin Matuska format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; 306caf54c4fSMartin Matuska archive_write_set_format(a, format); 307caf54c4fSMartin Matuska } 308caf54c4fSMartin Matuska if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0) 309caf54c4fSMartin Matuska lafe_errc(1, errno, "Could not seek to archive end"); 310caf54c4fSMartin Matuska if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) 311caf54c4fSMartin Matuska lafe_errc(1, 0, "%s", archive_error_string(a)); 312caf54c4fSMartin Matuska if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd)) 313caf54c4fSMartin Matuska lafe_errc(1, 0, "%s", archive_error_string(a)); 314caf54c4fSMartin Matuska 315caf54c4fSMartin Matuska write_archive(a, bsdtar); /* XXX check return val XXX */ 316caf54c4fSMartin Matuska 317caf54c4fSMartin Matuska close(bsdtar->fd); 318caf54c4fSMartin Matuska bsdtar->fd = -1; 319caf54c4fSMartin Matuska } 320caf54c4fSMartin Matuska 321caf54c4fSMartin Matuska void 322caf54c4fSMartin Matuska tar_mode_u(struct bsdtar *bsdtar) 323caf54c4fSMartin Matuska { 324caf54c4fSMartin Matuska int64_t end_offset; 325caf54c4fSMartin Matuska struct archive *a; 326caf54c4fSMartin Matuska struct archive_entry *entry; 327caf54c4fSMartin Matuska int format; 328caf54c4fSMartin Matuska struct archive_dir_entry *p; 329caf54c4fSMartin Matuska struct archive_dir archive_dir; 330caf54c4fSMartin Matuska 331caf54c4fSMartin Matuska bsdtar->archive_dir = &archive_dir; 332caf54c4fSMartin Matuska memset(&archive_dir, 0, sizeof(archive_dir)); 333caf54c4fSMartin Matuska 334caf54c4fSMartin Matuska format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; 335caf54c4fSMartin Matuska 336caf54c4fSMartin Matuska /* Sanity-test some arguments and the file. */ 337caf54c4fSMartin Matuska test_for_append(bsdtar); 338caf54c4fSMartin Matuska 339caf54c4fSMartin Matuska bsdtar->fd = open(bsdtar->filename, O_RDWR | O_BINARY); 340caf54c4fSMartin Matuska if (bsdtar->fd < 0) 341caf54c4fSMartin Matuska lafe_errc(1, errno, 342caf54c4fSMartin Matuska "Cannot open %s", bsdtar->filename); 343caf54c4fSMartin Matuska 344caf54c4fSMartin Matuska a = archive_read_new(); 345*6c95142eSMartin Matuska archive_read_support_filter_all(a); 346caf54c4fSMartin Matuska archive_read_support_format_tar(a); 347caf54c4fSMartin Matuska archive_read_support_format_gnutar(a); 348*6c95142eSMartin Matuska if (archive_read_open_fd(a, bsdtar->fd, bsdtar->bytes_per_block) 349*6c95142eSMartin Matuska != ARCHIVE_OK) { 350caf54c4fSMartin Matuska lafe_errc(1, 0, 351caf54c4fSMartin Matuska "Can't open %s: %s", bsdtar->filename, 352caf54c4fSMartin Matuska archive_error_string(a)); 353caf54c4fSMartin Matuska } 354caf54c4fSMartin Matuska 355caf54c4fSMartin Matuska /* Build a list of all entries and their recorded mod times. */ 356caf54c4fSMartin Matuska while (0 == archive_read_next_header(a, &entry)) { 357caf54c4fSMartin Matuska if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) { 358*6c95142eSMartin Matuska archive_read_free(a); 359caf54c4fSMartin Matuska close(bsdtar->fd); 360caf54c4fSMartin Matuska lafe_errc(1, 0, 361caf54c4fSMartin Matuska "Cannot append to compressed archive."); 362caf54c4fSMartin Matuska } 363caf54c4fSMartin Matuska add_dir_list(bsdtar, archive_entry_pathname(entry), 364caf54c4fSMartin Matuska archive_entry_mtime(entry), 365caf54c4fSMartin Matuska archive_entry_mtime_nsec(entry)); 366caf54c4fSMartin Matuska /* Record the last format determination we see */ 367caf54c4fSMartin Matuska format = archive_format(a); 368caf54c4fSMartin Matuska /* Keep going until we hit end-of-archive */ 369caf54c4fSMartin Matuska } 370caf54c4fSMartin Matuska 371caf54c4fSMartin Matuska end_offset = archive_read_header_position(a); 372*6c95142eSMartin Matuska archive_read_free(a); 373caf54c4fSMartin Matuska 374caf54c4fSMartin Matuska /* Re-open archive for writing. */ 375caf54c4fSMartin Matuska a = archive_write_new(); 376caf54c4fSMartin Matuska /* 377*6c95142eSMartin Matuska * Set format to same one auto-detected above. 378caf54c4fSMartin Matuska */ 379caf54c4fSMartin Matuska archive_write_set_format(a, format); 380caf54c4fSMartin Matuska archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); 381*6c95142eSMartin Matuska archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); 382*6c95142eSMartin Matuska 383caf54c4fSMartin Matuska if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0) 384caf54c4fSMartin Matuska lafe_errc(1, errno, "Could not seek to archive end"); 385caf54c4fSMartin Matuska if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) 386caf54c4fSMartin Matuska lafe_errc(1, 0, "%s", archive_error_string(a)); 387caf54c4fSMartin Matuska if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd)) 388caf54c4fSMartin Matuska lafe_errc(1, 0, "%s", archive_error_string(a)); 389caf54c4fSMartin Matuska 390caf54c4fSMartin Matuska write_archive(a, bsdtar); 391caf54c4fSMartin Matuska 392caf54c4fSMartin Matuska close(bsdtar->fd); 393caf54c4fSMartin Matuska bsdtar->fd = -1; 394caf54c4fSMartin Matuska 395caf54c4fSMartin Matuska while (bsdtar->archive_dir->head != NULL) { 396caf54c4fSMartin Matuska p = bsdtar->archive_dir->head->next; 397caf54c4fSMartin Matuska free(bsdtar->archive_dir->head->name); 398caf54c4fSMartin Matuska free(bsdtar->archive_dir->head); 399caf54c4fSMartin Matuska bsdtar->archive_dir->head = p; 400caf54c4fSMartin Matuska } 401caf54c4fSMartin Matuska bsdtar->archive_dir->tail = NULL; 402caf54c4fSMartin Matuska } 403caf54c4fSMartin Matuska 404caf54c4fSMartin Matuska 405caf54c4fSMartin Matuska /* 406caf54c4fSMartin Matuska * Write user-specified files/dirs to opened archive. 407caf54c4fSMartin Matuska */ 408caf54c4fSMartin Matuska static void 409caf54c4fSMartin Matuska write_archive(struct archive *a, struct bsdtar *bsdtar) 410caf54c4fSMartin Matuska { 411caf54c4fSMartin Matuska const char *arg; 412caf54c4fSMartin Matuska struct archive_entry *entry, *sparse_entry; 413caf54c4fSMartin Matuska 414*6c95142eSMartin Matuska /* Choose a suitable copy buffer size */ 415*6c95142eSMartin Matuska bsdtar->buff_size = 64 * 1024; 416*6c95142eSMartin Matuska while (bsdtar->buff_size < (size_t)bsdtar->bytes_per_block) 417*6c95142eSMartin Matuska bsdtar->buff_size *= 2; 418*6c95142eSMartin Matuska /* Try to compensate for space we'll lose to alignment. */ 419*6c95142eSMartin Matuska bsdtar->buff_size += 16 * 1024; 420*6c95142eSMartin Matuska 421caf54c4fSMartin Matuska /* Allocate a buffer for file data. */ 422*6c95142eSMartin Matuska if ((bsdtar->buff = malloc(bsdtar->buff_size)) == NULL) 423caf54c4fSMartin Matuska lafe_errc(1, 0, "cannot allocate memory"); 424caf54c4fSMartin Matuska 425caf54c4fSMartin Matuska if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL) 426caf54c4fSMartin Matuska lafe_errc(1, 0, "cannot create link resolver"); 427caf54c4fSMartin Matuska archive_entry_linkresolver_set_strategy(bsdtar->resolver, 428caf54c4fSMartin Matuska archive_format(a)); 429caf54c4fSMartin Matuska if ((bsdtar->diskreader = archive_read_disk_new()) == NULL) 430caf54c4fSMartin Matuska lafe_errc(1, 0, "Cannot create read_disk object"); 431caf54c4fSMartin Matuska archive_read_disk_set_standard_lookup(bsdtar->diskreader); 432caf54c4fSMartin Matuska 433caf54c4fSMartin Matuska if (bsdtar->names_from_file != NULL) 434caf54c4fSMartin Matuska archive_names_from_file(bsdtar, a); 435caf54c4fSMartin Matuska 436caf54c4fSMartin Matuska while (*bsdtar->argv) { 437caf54c4fSMartin Matuska arg = *bsdtar->argv; 438caf54c4fSMartin Matuska if (arg[0] == '-' && arg[1] == 'C') { 439caf54c4fSMartin Matuska arg += 2; 440caf54c4fSMartin Matuska if (*arg == '\0') { 441caf54c4fSMartin Matuska bsdtar->argv++; 442caf54c4fSMartin Matuska arg = *bsdtar->argv; 443caf54c4fSMartin Matuska if (arg == NULL) { 444caf54c4fSMartin Matuska lafe_warnc(0, "%s", 445caf54c4fSMartin Matuska "Missing argument for -C"); 446caf54c4fSMartin Matuska bsdtar->return_value = 1; 447caf54c4fSMartin Matuska goto cleanup; 448caf54c4fSMartin Matuska } 449*6c95142eSMartin Matuska if (*arg == '\0') { 450*6c95142eSMartin Matuska lafe_warnc(0, 451*6c95142eSMartin Matuska "Meaningless argument for -C: ''"); 452*6c95142eSMartin Matuska bsdtar->return_value = 1; 453*6c95142eSMartin Matuska goto cleanup; 454*6c95142eSMartin Matuska } 455caf54c4fSMartin Matuska } 456caf54c4fSMartin Matuska set_chdir(bsdtar, arg); 457caf54c4fSMartin Matuska } else { 458caf54c4fSMartin Matuska if (*arg != '/' && (arg[0] != '@' || arg[1] != '/')) 459caf54c4fSMartin Matuska do_chdir(bsdtar); /* Handle a deferred -C */ 460caf54c4fSMartin Matuska if (*arg == '@') { 461caf54c4fSMartin Matuska if (append_archive_filename(bsdtar, a, 462caf54c4fSMartin Matuska arg + 1) != 0) 463caf54c4fSMartin Matuska break; 464caf54c4fSMartin Matuska } else 465caf54c4fSMartin Matuska write_hierarchy(bsdtar, a, arg); 466caf54c4fSMartin Matuska } 467caf54c4fSMartin Matuska bsdtar->argv++; 468caf54c4fSMartin Matuska } 469caf54c4fSMartin Matuska 470caf54c4fSMartin Matuska entry = NULL; 471caf54c4fSMartin Matuska archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); 472caf54c4fSMartin Matuska while (entry != NULL) { 473*6c95142eSMartin Matuska write_file(bsdtar, a, entry); 474caf54c4fSMartin Matuska archive_entry_free(entry); 475caf54c4fSMartin Matuska entry = NULL; 476caf54c4fSMartin Matuska archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); 477caf54c4fSMartin Matuska } 478caf54c4fSMartin Matuska 479caf54c4fSMartin Matuska if (archive_write_close(a)) { 480caf54c4fSMartin Matuska lafe_warnc(0, "%s", archive_error_string(a)); 481caf54c4fSMartin Matuska bsdtar->return_value = 1; 482caf54c4fSMartin Matuska } 483caf54c4fSMartin Matuska 484caf54c4fSMartin Matuska cleanup: 485caf54c4fSMartin Matuska /* Free file data buffer. */ 486caf54c4fSMartin Matuska free(bsdtar->buff); 487caf54c4fSMartin Matuska archive_entry_linkresolver_free(bsdtar->resolver); 488caf54c4fSMartin Matuska bsdtar->resolver = NULL; 489*6c95142eSMartin Matuska archive_read_free(bsdtar->diskreader); 490caf54c4fSMartin Matuska bsdtar->diskreader = NULL; 491caf54c4fSMartin Matuska 492caf54c4fSMartin Matuska if (bsdtar->option_totals) { 493caf54c4fSMartin Matuska fprintf(stderr, "Total bytes written: %s\n", 494caf54c4fSMartin Matuska tar_i64toa(archive_position_compressed(a))); 495caf54c4fSMartin Matuska } 496caf54c4fSMartin Matuska 497*6c95142eSMartin Matuska archive_write_free(a); 498caf54c4fSMartin Matuska } 499caf54c4fSMartin Matuska 500caf54c4fSMartin Matuska /* 501caf54c4fSMartin Matuska * Archive names specified in file. 502caf54c4fSMartin Matuska * 503caf54c4fSMartin Matuska * Unless --null was specified, a line containing exactly "-C" will 504caf54c4fSMartin Matuska * cause the next line to be a directory to pass to chdir(). If 505caf54c4fSMartin Matuska * --null is specified, then a line "-C" is just another filename. 506caf54c4fSMartin Matuska */ 507caf54c4fSMartin Matuska static void 508caf54c4fSMartin Matuska archive_names_from_file(struct bsdtar *bsdtar, struct archive *a) 509caf54c4fSMartin Matuska { 510caf54c4fSMartin Matuska struct lafe_line_reader *lr; 511caf54c4fSMartin Matuska const char *line; 512caf54c4fSMartin Matuska 513caf54c4fSMartin Matuska bsdtar->next_line_is_dir = 0; 514caf54c4fSMartin Matuska 515caf54c4fSMartin Matuska lr = lafe_line_reader(bsdtar->names_from_file, bsdtar->option_null); 516caf54c4fSMartin Matuska while ((line = lafe_line_reader_next(lr)) != NULL) { 517caf54c4fSMartin Matuska if (bsdtar->next_line_is_dir) { 518*6c95142eSMartin Matuska if (*line != '\0') 519caf54c4fSMartin Matuska set_chdir(bsdtar, line); 520*6c95142eSMartin Matuska else { 521*6c95142eSMartin Matuska lafe_warnc(0, 522*6c95142eSMartin Matuska "Meaningless argument for -C: ''"); 523*6c95142eSMartin Matuska bsdtar->return_value = 1; 524*6c95142eSMartin Matuska } 525caf54c4fSMartin Matuska bsdtar->next_line_is_dir = 0; 526caf54c4fSMartin Matuska } else if (!bsdtar->option_null && strcmp(line, "-C") == 0) 527caf54c4fSMartin Matuska bsdtar->next_line_is_dir = 1; 528caf54c4fSMartin Matuska else { 529caf54c4fSMartin Matuska if (*line != '/') 530caf54c4fSMartin Matuska do_chdir(bsdtar); /* Handle a deferred -C */ 531caf54c4fSMartin Matuska write_hierarchy(bsdtar, a, line); 532caf54c4fSMartin Matuska } 533caf54c4fSMartin Matuska } 534caf54c4fSMartin Matuska lafe_line_reader_free(lr); 535caf54c4fSMartin Matuska if (bsdtar->next_line_is_dir) 536caf54c4fSMartin Matuska lafe_errc(1, errno, 537caf54c4fSMartin Matuska "Unexpected end of filename list; " 538caf54c4fSMartin Matuska "directory expected after -C"); 539caf54c4fSMartin Matuska } 540caf54c4fSMartin Matuska 541caf54c4fSMartin Matuska /* 542caf54c4fSMartin Matuska * Copy from specified archive to current archive. Returns non-zero 543caf54c4fSMartin Matuska * for write errors (which force us to terminate the entire archiving 544caf54c4fSMartin Matuska * operation). If there are errors reading the input archive, we set 545caf54c4fSMartin Matuska * bsdtar->return_value but return zero, so the overall archiving 546caf54c4fSMartin Matuska * operation will complete and return non-zero. 547caf54c4fSMartin Matuska */ 548caf54c4fSMartin Matuska static int 549caf54c4fSMartin Matuska append_archive_filename(struct bsdtar *bsdtar, struct archive *a, 550*6c95142eSMartin Matuska const char *raw_filename) 551caf54c4fSMartin Matuska { 552caf54c4fSMartin Matuska struct archive *ina; 553*6c95142eSMartin Matuska const char *filename = raw_filename; 554caf54c4fSMartin Matuska int rc; 555caf54c4fSMartin Matuska 556caf54c4fSMartin Matuska if (strcmp(filename, "-") == 0) 557caf54c4fSMartin Matuska filename = NULL; /* Library uses NULL for stdio. */ 558caf54c4fSMartin Matuska 559caf54c4fSMartin Matuska ina = archive_read_new(); 560caf54c4fSMartin Matuska archive_read_support_format_all(ina); 561*6c95142eSMartin Matuska archive_read_support_filter_all(ina); 562*6c95142eSMartin Matuska if (archive_read_open_file(ina, filename, bsdtar->bytes_per_block)) { 563caf54c4fSMartin Matuska lafe_warnc(0, "%s", archive_error_string(ina)); 564caf54c4fSMartin Matuska bsdtar->return_value = 1; 565caf54c4fSMartin Matuska return (0); 566caf54c4fSMartin Matuska } 567caf54c4fSMartin Matuska 568caf54c4fSMartin Matuska rc = append_archive(bsdtar, a, ina); 569caf54c4fSMartin Matuska 570caf54c4fSMartin Matuska if (rc != ARCHIVE_OK) { 571caf54c4fSMartin Matuska lafe_warnc(0, "Error reading archive %s: %s", 572*6c95142eSMartin Matuska raw_filename, archive_error_string(ina)); 573caf54c4fSMartin Matuska bsdtar->return_value = 1; 574caf54c4fSMartin Matuska } 575*6c95142eSMartin Matuska archive_read_free(ina); 576caf54c4fSMartin Matuska 577caf54c4fSMartin Matuska return (rc); 578caf54c4fSMartin Matuska } 579caf54c4fSMartin Matuska 580caf54c4fSMartin Matuska static int 581caf54c4fSMartin Matuska append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) 582caf54c4fSMartin Matuska { 583caf54c4fSMartin Matuska struct archive_entry *in_entry; 584caf54c4fSMartin Matuska int e; 585caf54c4fSMartin Matuska 586caf54c4fSMartin Matuska while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) { 587caf54c4fSMartin Matuska if (!new_enough(bsdtar, archive_entry_pathname(in_entry), 588caf54c4fSMartin Matuska archive_entry_stat(in_entry))) 589caf54c4fSMartin Matuska continue; 590caf54c4fSMartin Matuska if (lafe_excluded(bsdtar->matching, archive_entry_pathname(in_entry))) 591caf54c4fSMartin Matuska continue; 592caf54c4fSMartin Matuska if (bsdtar->option_interactive && 593caf54c4fSMartin Matuska !yes("copy '%s'", archive_entry_pathname(in_entry))) 594caf54c4fSMartin Matuska continue; 595caf54c4fSMartin Matuska if (bsdtar->verbose) 596caf54c4fSMartin Matuska safe_fprintf(stderr, "a %s", 597caf54c4fSMartin Matuska archive_entry_pathname(in_entry)); 598caf54c4fSMartin Matuska if (need_report()) 599caf54c4fSMartin Matuska report_write(bsdtar, a, in_entry, 0); 600caf54c4fSMartin Matuska 601caf54c4fSMartin Matuska e = archive_write_header(a, in_entry); 602caf54c4fSMartin Matuska if (e != ARCHIVE_OK) { 603caf54c4fSMartin Matuska if (!bsdtar->verbose) 604caf54c4fSMartin Matuska lafe_warnc(0, "%s: %s", 605caf54c4fSMartin Matuska archive_entry_pathname(in_entry), 606caf54c4fSMartin Matuska archive_error_string(a)); 607caf54c4fSMartin Matuska else 608caf54c4fSMartin Matuska fprintf(stderr, ": %s", archive_error_string(a)); 609caf54c4fSMartin Matuska } 610caf54c4fSMartin Matuska if (e == ARCHIVE_FATAL) 611caf54c4fSMartin Matuska exit(1); 612caf54c4fSMartin Matuska 613caf54c4fSMartin Matuska if (e >= ARCHIVE_WARN) { 614caf54c4fSMartin Matuska if (archive_entry_size(in_entry) == 0) 615caf54c4fSMartin Matuska archive_read_data_skip(ina); 616caf54c4fSMartin Matuska else if (copy_file_data(bsdtar, a, ina, in_entry)) 617caf54c4fSMartin Matuska exit(1); 618caf54c4fSMartin Matuska } 619caf54c4fSMartin Matuska 620caf54c4fSMartin Matuska if (bsdtar->verbose) 621caf54c4fSMartin Matuska fprintf(stderr, "\n"); 622caf54c4fSMartin Matuska } 623caf54c4fSMartin Matuska 624caf54c4fSMartin Matuska return (e == ARCHIVE_EOF ? ARCHIVE_OK : e); 625caf54c4fSMartin Matuska } 626caf54c4fSMartin Matuska 627caf54c4fSMartin Matuska /* Helper function to copy data between archives. */ 628caf54c4fSMartin Matuska static int 629caf54c4fSMartin Matuska copy_file_data(struct bsdtar *bsdtar, struct archive *a, 630caf54c4fSMartin Matuska struct archive *ina, struct archive_entry *entry) 631caf54c4fSMartin Matuska { 632caf54c4fSMartin Matuska ssize_t bytes_read; 633caf54c4fSMartin Matuska ssize_t bytes_written; 634caf54c4fSMartin Matuska int64_t progress = 0; 635caf54c4fSMartin Matuska 636*6c95142eSMartin Matuska bytes_read = archive_read_data(ina, bsdtar->buff, bsdtar->buff_size); 637caf54c4fSMartin Matuska while (bytes_read > 0) { 638caf54c4fSMartin Matuska if (need_report()) 639caf54c4fSMartin Matuska report_write(bsdtar, a, entry, progress); 640caf54c4fSMartin Matuska 641caf54c4fSMartin Matuska bytes_written = archive_write_data(a, bsdtar->buff, 642caf54c4fSMartin Matuska bytes_read); 643caf54c4fSMartin Matuska if (bytes_written < bytes_read) { 644caf54c4fSMartin Matuska lafe_warnc(0, "%s", archive_error_string(a)); 645caf54c4fSMartin Matuska return (-1); 646caf54c4fSMartin Matuska } 647caf54c4fSMartin Matuska progress += bytes_written; 648*6c95142eSMartin Matuska bytes_read = archive_read_data(ina, bsdtar->buff, bsdtar->buff_size); 649caf54c4fSMartin Matuska } 650caf54c4fSMartin Matuska 651caf54c4fSMartin Matuska return (0); 652caf54c4fSMartin Matuska } 653caf54c4fSMartin Matuska 654caf54c4fSMartin Matuska /* 655caf54c4fSMartin Matuska * Add the file or dir hierarchy named by 'path' to the archive 656caf54c4fSMartin Matuska */ 657caf54c4fSMartin Matuska static void 658caf54c4fSMartin Matuska write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) 659caf54c4fSMartin Matuska { 660caf54c4fSMartin Matuska struct archive_entry *entry = NULL, *spare_entry = NULL; 661caf54c4fSMartin Matuska struct tree *tree; 662caf54c4fSMartin Matuska char symlink_mode = bsdtar->symlink_mode; 663caf54c4fSMartin Matuska dev_t first_dev = 0; 664caf54c4fSMartin Matuska int dev_recorded = 0; 665caf54c4fSMartin Matuska int tree_ret; 666caf54c4fSMartin Matuska 667caf54c4fSMartin Matuska tree = tree_open(path); 668caf54c4fSMartin Matuska 669caf54c4fSMartin Matuska if (!tree) { 670caf54c4fSMartin Matuska lafe_warnc(errno, "%s: Cannot open", path); 671caf54c4fSMartin Matuska bsdtar->return_value = 1; 672caf54c4fSMartin Matuska return; 673caf54c4fSMartin Matuska } 674caf54c4fSMartin Matuska 675caf54c4fSMartin Matuska while ((tree_ret = tree_next(tree)) != 0) { 676caf54c4fSMartin Matuska int r; 677caf54c4fSMartin Matuska const char *name = tree_current_path(tree); 678caf54c4fSMartin Matuska const struct stat *st = NULL; /* info to use for this entry */ 679caf54c4fSMartin Matuska const struct stat *lst = NULL; /* lstat() information */ 680caf54c4fSMartin Matuska int descend; 681caf54c4fSMartin Matuska 682caf54c4fSMartin Matuska if (tree_ret == TREE_ERROR_FATAL) 683caf54c4fSMartin Matuska lafe_errc(1, tree_errno(tree), 684caf54c4fSMartin Matuska "%s: Unable to continue traversing directory tree", 685caf54c4fSMartin Matuska name); 686caf54c4fSMartin Matuska if (tree_ret == TREE_ERROR_DIR) { 687caf54c4fSMartin Matuska lafe_warnc(errno, 688caf54c4fSMartin Matuska "%s: Couldn't visit directory", name); 689caf54c4fSMartin Matuska bsdtar->return_value = 1; 690caf54c4fSMartin Matuska } 691caf54c4fSMartin Matuska if (tree_ret != TREE_REGULAR) 692caf54c4fSMartin Matuska continue; 693caf54c4fSMartin Matuska 694caf54c4fSMartin Matuska /* 695caf54c4fSMartin Matuska * If this file/dir is excluded by a filename 696caf54c4fSMartin Matuska * pattern, skip it. 697caf54c4fSMartin Matuska */ 698caf54c4fSMartin Matuska if (lafe_excluded(bsdtar->matching, name)) 699caf54c4fSMartin Matuska continue; 700caf54c4fSMartin Matuska 701caf54c4fSMartin Matuska /* 702caf54c4fSMartin Matuska * Get lstat() info from the tree library. 703caf54c4fSMartin Matuska */ 704caf54c4fSMartin Matuska lst = tree_current_lstat(tree); 705caf54c4fSMartin Matuska if (lst == NULL) { 706caf54c4fSMartin Matuska /* Couldn't lstat(); must not exist. */ 707caf54c4fSMartin Matuska lafe_warnc(errno, "%s: Cannot stat", name); 708caf54c4fSMartin Matuska /* Return error if files disappear during traverse. */ 709caf54c4fSMartin Matuska bsdtar->return_value = 1; 710caf54c4fSMartin Matuska continue; 711caf54c4fSMartin Matuska } 712caf54c4fSMartin Matuska 713caf54c4fSMartin Matuska /* 714caf54c4fSMartin Matuska * Distinguish 'L'/'P'/'H' symlink following. 715caf54c4fSMartin Matuska */ 716caf54c4fSMartin Matuska switch(symlink_mode) { 717caf54c4fSMartin Matuska case 'H': 718caf54c4fSMartin Matuska /* 'H': After the first item, rest like 'P'. */ 719caf54c4fSMartin Matuska symlink_mode = 'P'; 720caf54c4fSMartin Matuska /* 'H': First item (from command line) like 'L'. */ 721caf54c4fSMartin Matuska /* FALLTHROUGH */ 722caf54c4fSMartin Matuska case 'L': 723caf54c4fSMartin Matuska /* 'L': Do descend through a symlink to dir. */ 724caf54c4fSMartin Matuska descend = tree_current_is_dir(tree); 725caf54c4fSMartin Matuska /* 'L': Follow symlinks to files. */ 726caf54c4fSMartin Matuska archive_read_disk_set_symlink_logical(bsdtar->diskreader); 727caf54c4fSMartin Matuska /* 'L': Archive symlinks as targets, if we can. */ 728caf54c4fSMartin Matuska st = tree_current_stat(tree); 729caf54c4fSMartin Matuska if (st != NULL) 730caf54c4fSMartin Matuska break; 731caf54c4fSMartin Matuska /* If stat fails, we have a broken symlink; 732caf54c4fSMartin Matuska * in that case, don't follow the link. */ 733caf54c4fSMartin Matuska /* FALLTHROUGH */ 734caf54c4fSMartin Matuska default: 735caf54c4fSMartin Matuska /* 'P': Don't descend through a symlink to dir. */ 736caf54c4fSMartin Matuska descend = tree_current_is_physical_dir(tree); 737caf54c4fSMartin Matuska /* 'P': Don't follow symlinks to files. */ 738caf54c4fSMartin Matuska archive_read_disk_set_symlink_physical(bsdtar->diskreader); 739caf54c4fSMartin Matuska /* 'P': Archive symlinks as symlinks. */ 740caf54c4fSMartin Matuska st = lst; 741caf54c4fSMartin Matuska break; 742caf54c4fSMartin Matuska } 743caf54c4fSMartin Matuska 744c5d360f8SMartin Matuska if (bsdtar->option_no_subdirs) 745c5d360f8SMartin Matuska descend = 0; 746c5d360f8SMartin Matuska 747caf54c4fSMartin Matuska /* 748caf54c4fSMartin Matuska * Are we about to cross to a new filesystem? 749caf54c4fSMartin Matuska */ 750caf54c4fSMartin Matuska if (!dev_recorded) { 751caf54c4fSMartin Matuska /* This is the initial file system. */ 752caf54c4fSMartin Matuska first_dev = lst->st_dev; 753caf54c4fSMartin Matuska dev_recorded = 1; 754caf54c4fSMartin Matuska } else if (lst->st_dev == first_dev) { 755caf54c4fSMartin Matuska /* The starting file system is always acceptable. */ 756caf54c4fSMartin Matuska } else if (descend == 0) { 757caf54c4fSMartin Matuska /* We're not descending, so no need to check. */ 758caf54c4fSMartin Matuska } else if (bsdtar->option_dont_traverse_mounts) { 759caf54c4fSMartin Matuska descend = 0; 760caf54c4fSMartin Matuska } else { 761caf54c4fSMartin Matuska /* We're prepared to cross a mount point. */ 762caf54c4fSMartin Matuska 763caf54c4fSMartin Matuska /* XXX TODO: check whether this filesystem is 764caf54c4fSMartin Matuska * synthetic and/or local. Add a new 765caf54c4fSMartin Matuska * --local-only option to skip non-local 766caf54c4fSMartin Matuska * filesystems. Skip synthetic filesystems 767caf54c4fSMartin Matuska * regardless. 768caf54c4fSMartin Matuska * 769caf54c4fSMartin Matuska * The results should be cached, since 770caf54c4fSMartin Matuska * tree.c doesn't usually visit a directory 771caf54c4fSMartin Matuska * and the directory contents together. A simple 772caf54c4fSMartin Matuska * move-to-front list should perform quite well. 773caf54c4fSMartin Matuska * 774caf54c4fSMartin Matuska * This is going to be heavily OS dependent: 775caf54c4fSMartin Matuska * FreeBSD's statfs() in conjunction with getvfsbyname() 776caf54c4fSMartin Matuska * provides all of this; NetBSD's statvfs() does 777caf54c4fSMartin Matuska * most of it; other systems will vary. 778caf54c4fSMartin Matuska */ 779caf54c4fSMartin Matuska } 780caf54c4fSMartin Matuska 781caf54c4fSMartin Matuska /* 782caf54c4fSMartin Matuska * In -u mode, check that the file is newer than what's 783caf54c4fSMartin Matuska * already in the archive; in all modes, obey --newerXXX flags. 784caf54c4fSMartin Matuska */ 785c5d360f8SMartin Matuska if (!new_enough(bsdtar, name, st)) { 786c5d360f8SMartin Matuska if (!descend) 787caf54c4fSMartin Matuska continue; 788c5d360f8SMartin Matuska if (bsdtar->option_interactive && 789c5d360f8SMartin Matuska !yes("add '%s'", name)) 790c5d360f8SMartin Matuska continue; 791c5d360f8SMartin Matuska tree_descend(tree); 792c5d360f8SMartin Matuska continue; 793c5d360f8SMartin Matuska } 794caf54c4fSMartin Matuska 795caf54c4fSMartin Matuska archive_entry_free(entry); 796caf54c4fSMartin Matuska entry = archive_entry_new(); 797caf54c4fSMartin Matuska 798caf54c4fSMartin Matuska archive_entry_set_pathname(entry, name); 799caf54c4fSMartin Matuska archive_entry_copy_sourcepath(entry, 800caf54c4fSMartin Matuska tree_current_access_path(tree)); 801caf54c4fSMartin Matuska 802caf54c4fSMartin Matuska /* Populate the archive_entry with metadata from the disk. */ 803caf54c4fSMartin Matuska /* XXX TODO: Arrange to open a regular file before 804caf54c4fSMartin Matuska * calling this so we can pass in an fd and shorten 805caf54c4fSMartin Matuska * the race to query metadata. The linkify dance 806caf54c4fSMartin Matuska * makes this more complex than it might sound. */ 807caf54c4fSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 808caf54c4fSMartin Matuska /* TODO: tree.c uses stat(), which is badly broken 809caf54c4fSMartin Matuska * on Windows. To fix this, we should 810caf54c4fSMartin Matuska * deprecate tree_current_stat() and provide a new 811caf54c4fSMartin Matuska * call tree_populate_entry(t, entry). This call 812caf54c4fSMartin Matuska * would use stat() internally on POSIX and 813caf54c4fSMartin Matuska * GetInfoByFileHandle() internally on Windows. 814caf54c4fSMartin Matuska * This would be another step towards a tree-walker 815caf54c4fSMartin Matuska * that can be integrated deep into libarchive. 816caf54c4fSMartin Matuska * For now, just set st to NULL on Windows; 817caf54c4fSMartin Matuska * archive_read_disk_entry_from_file() should 818caf54c4fSMartin Matuska * be smart enough to use platform-appropriate 819caf54c4fSMartin Matuska * ways to probe file information. 820caf54c4fSMartin Matuska */ 821caf54c4fSMartin Matuska st = NULL; 822caf54c4fSMartin Matuska #endif 823caf54c4fSMartin Matuska r = archive_read_disk_entry_from_file(bsdtar->diskreader, 824caf54c4fSMartin Matuska entry, -1, st); 825caf54c4fSMartin Matuska if (bsdtar->uid >= 0) { 826caf54c4fSMartin Matuska archive_entry_set_uid(entry, bsdtar->uid); 827caf54c4fSMartin Matuska if (!bsdtar->uname) 828caf54c4fSMartin Matuska archive_entry_set_uname(entry, 829caf54c4fSMartin Matuska archive_read_disk_uname(bsdtar->diskreader, 830caf54c4fSMartin Matuska bsdtar->uid)); 831caf54c4fSMartin Matuska } 832caf54c4fSMartin Matuska if (bsdtar->gid >= 0) { 833caf54c4fSMartin Matuska archive_entry_set_gid(entry, bsdtar->gid); 834caf54c4fSMartin Matuska if (!bsdtar->gname) 835caf54c4fSMartin Matuska archive_entry_set_gname(entry, 836caf54c4fSMartin Matuska archive_read_disk_gname(bsdtar->diskreader, 837caf54c4fSMartin Matuska bsdtar->gid)); 838caf54c4fSMartin Matuska } 839caf54c4fSMartin Matuska if (bsdtar->uname) 840caf54c4fSMartin Matuska archive_entry_set_uname(entry, bsdtar->uname); 841caf54c4fSMartin Matuska if (bsdtar->gname) 842caf54c4fSMartin Matuska archive_entry_set_gname(entry, bsdtar->gname); 843caf54c4fSMartin Matuska if (r != ARCHIVE_OK) 844caf54c4fSMartin Matuska lafe_warnc(archive_errno(bsdtar->diskreader), 845caf54c4fSMartin Matuska "%s", archive_error_string(bsdtar->diskreader)); 846caf54c4fSMartin Matuska if (r < ARCHIVE_WARN) 847caf54c4fSMartin Matuska continue; 848caf54c4fSMartin Matuska 849caf54c4fSMartin Matuska /* XXX TODO: Just use flag data from entry; avoid the 850caf54c4fSMartin Matuska * duplicate check here. */ 851caf54c4fSMartin Matuska 852caf54c4fSMartin Matuska /* 853caf54c4fSMartin Matuska * If this file/dir is flagged "nodump" and we're 854caf54c4fSMartin Matuska * honoring such flags, skip this file/dir. 855caf54c4fSMartin Matuska */ 856caf54c4fSMartin Matuska #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) 857caf54c4fSMartin Matuska /* BSD systems store flags in struct stat */ 858caf54c4fSMartin Matuska if (bsdtar->option_honor_nodump && 859caf54c4fSMartin Matuska (lst->st_flags & UF_NODUMP)) 860caf54c4fSMartin Matuska continue; 861caf54c4fSMartin Matuska #endif 862caf54c4fSMartin Matuska 863*6c95142eSMartin Matuska #if defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) 864caf54c4fSMartin Matuska /* Linux uses ioctl to read flags. */ 865caf54c4fSMartin Matuska if (bsdtar->option_honor_nodump) { 866caf54c4fSMartin Matuska int fd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY); 867caf54c4fSMartin Matuska if (fd >= 0) { 868caf54c4fSMartin Matuska unsigned long fflags; 869caf54c4fSMartin Matuska int r = ioctl(fd, EXT2_IOC_GETFLAGS, &fflags); 870caf54c4fSMartin Matuska close(fd); 871caf54c4fSMartin Matuska if (r >= 0 && (fflags & EXT2_NODUMP_FL)) 872caf54c4fSMartin Matuska continue; 873caf54c4fSMartin Matuska } 874caf54c4fSMartin Matuska } 875caf54c4fSMartin Matuska #endif 876caf54c4fSMartin Matuska 877*6c95142eSMartin Matuska #ifdef __APPLE__ 878*6c95142eSMartin Matuska if (bsdtar->enable_copyfile) { 879*6c95142eSMartin Matuska /* If we're using copyfile(), ignore "._XXX" files. */ 880*6c95142eSMartin Matuska const char *bname = strrchr(name, '/'); 881*6c95142eSMartin Matuska if (bname == NULL) 882*6c95142eSMartin Matuska bname = name; 883*6c95142eSMartin Matuska else 884*6c95142eSMartin Matuska ++bname; 885*6c95142eSMartin Matuska if (bname[0] == '.' && bname[1] == '_') 886*6c95142eSMartin Matuska continue; 887*6c95142eSMartin Matuska } else { 888*6c95142eSMartin Matuska /* If not, drop the copyfile() data. */ 889*6c95142eSMartin Matuska archive_entry_copy_mac_metadata(entry, NULL, 0); 890*6c95142eSMartin Matuska } 891*6c95142eSMartin Matuska #endif 892*6c95142eSMartin Matuska 893caf54c4fSMartin Matuska /* 894caf54c4fSMartin Matuska * If the user vetoes this file/directory, skip it. 895caf54c4fSMartin Matuska * We want this to be fairly late; if some other 896caf54c4fSMartin Matuska * check would veto this file, we shouldn't bother 897caf54c4fSMartin Matuska * the user with it. 898caf54c4fSMartin Matuska */ 899caf54c4fSMartin Matuska if (bsdtar->option_interactive && 900caf54c4fSMartin Matuska !yes("add '%s'", name)) 901caf54c4fSMartin Matuska continue; 902caf54c4fSMartin Matuska 903c5d360f8SMartin Matuska if (descend) 904caf54c4fSMartin Matuska tree_descend(tree); 905caf54c4fSMartin Matuska 906caf54c4fSMartin Matuska /* 907caf54c4fSMartin Matuska * Rewrite the pathname to be archived. If rewrite 908caf54c4fSMartin Matuska * fails, skip the entry. 909caf54c4fSMartin Matuska */ 910caf54c4fSMartin Matuska if (edit_pathname(bsdtar, entry)) 911caf54c4fSMartin Matuska continue; 912caf54c4fSMartin Matuska 913caf54c4fSMartin Matuska /* Display entry as we process it. 914caf54c4fSMartin Matuska * This format is required by SUSv2. */ 915caf54c4fSMartin Matuska if (bsdtar->verbose) 916caf54c4fSMartin Matuska safe_fprintf(stderr, "a %s", 917caf54c4fSMartin Matuska archive_entry_pathname(entry)); 918caf54c4fSMartin Matuska 919caf54c4fSMartin Matuska /* Non-regular files get archived with zero size. */ 920caf54c4fSMartin Matuska if (archive_entry_filetype(entry) != AE_IFREG) 921caf54c4fSMartin Matuska archive_entry_set_size(entry, 0); 922caf54c4fSMartin Matuska 923caf54c4fSMartin Matuska archive_entry_linkify(bsdtar->resolver, &entry, &spare_entry); 924caf54c4fSMartin Matuska 925caf54c4fSMartin Matuska while (entry != NULL) { 926*6c95142eSMartin Matuska write_file(bsdtar, a, entry); 927caf54c4fSMartin Matuska archive_entry_free(entry); 928caf54c4fSMartin Matuska entry = spare_entry; 929caf54c4fSMartin Matuska spare_entry = NULL; 930caf54c4fSMartin Matuska } 931caf54c4fSMartin Matuska 932caf54c4fSMartin Matuska if (bsdtar->verbose) 933caf54c4fSMartin Matuska fprintf(stderr, "\n"); 934caf54c4fSMartin Matuska } 935caf54c4fSMartin Matuska archive_entry_free(entry); 936caf54c4fSMartin Matuska tree_close(tree); 937caf54c4fSMartin Matuska } 938caf54c4fSMartin Matuska 939caf54c4fSMartin Matuska /* 940*6c95142eSMartin Matuska * Write a single file (or directory or other filesystem object) to 941*6c95142eSMartin Matuska * the archive. 942caf54c4fSMartin Matuska */ 943caf54c4fSMartin Matuska static void 944*6c95142eSMartin Matuska write_file(struct bsdtar *bsdtar, struct archive *a, 945*6c95142eSMartin Matuska struct archive_entry *entry) 946*6c95142eSMartin Matuska { 947*6c95142eSMartin Matuska write_entry(bsdtar, a, entry); 948*6c95142eSMartin Matuska } 949*6c95142eSMartin Matuska 950*6c95142eSMartin Matuska /* 951*6c95142eSMartin Matuska * Write a single entry to the archive. 952*6c95142eSMartin Matuska */ 953*6c95142eSMartin Matuska static void 954*6c95142eSMartin Matuska write_entry(struct bsdtar *bsdtar, struct archive *a, 955caf54c4fSMartin Matuska struct archive_entry *entry) 956caf54c4fSMartin Matuska { 957caf54c4fSMartin Matuska int fd = -1; 958caf54c4fSMartin Matuska int e; 959*6c95142eSMartin Matuska size_t align = 4096; 960caf54c4fSMartin Matuska 961caf54c4fSMartin Matuska if (archive_entry_size(entry) > 0) { 962caf54c4fSMartin Matuska const char *pathname = archive_entry_sourcepath(entry); 963*6c95142eSMartin Matuska /* TODO: Use O_DIRECT here and set 'align' to the 964*6c95142eSMartin Matuska * actual filesystem block size. As of July 2010, new 965*6c95142eSMartin Matuska * directory-traversal code is going in that will make 966*6c95142eSMartin Matuska * it much easier to track filesystem properties like 967*6c95142eSMartin Matuska * this during the traversal. */ 968caf54c4fSMartin Matuska fd = open(pathname, O_RDONLY | O_BINARY); 969*6c95142eSMartin Matuska align = 4096; 970caf54c4fSMartin Matuska if (fd == -1) { 971c5d360f8SMartin Matuska bsdtar->return_value = 1; 972caf54c4fSMartin Matuska if (!bsdtar->verbose) 973caf54c4fSMartin Matuska lafe_warnc(errno, 974caf54c4fSMartin Matuska "%s: could not open file", pathname); 975caf54c4fSMartin Matuska else 976caf54c4fSMartin Matuska fprintf(stderr, ": %s", strerror(errno)); 977caf54c4fSMartin Matuska return; 978caf54c4fSMartin Matuska } 979caf54c4fSMartin Matuska } 980caf54c4fSMartin Matuska 981caf54c4fSMartin Matuska e = archive_write_header(a, entry); 982caf54c4fSMartin Matuska if (e != ARCHIVE_OK) { 983caf54c4fSMartin Matuska if (!bsdtar->verbose) 984caf54c4fSMartin Matuska lafe_warnc(0, "%s: %s", 985caf54c4fSMartin Matuska archive_entry_pathname(entry), 986caf54c4fSMartin Matuska archive_error_string(a)); 987caf54c4fSMartin Matuska else 988caf54c4fSMartin Matuska fprintf(stderr, ": %s", archive_error_string(a)); 989caf54c4fSMartin Matuska } 990caf54c4fSMartin Matuska 991caf54c4fSMartin Matuska if (e == ARCHIVE_FATAL) 992caf54c4fSMartin Matuska exit(1); 993caf54c4fSMartin Matuska 994caf54c4fSMartin Matuska /* 995caf54c4fSMartin Matuska * If we opened a file earlier, write it out now. Note that 996caf54c4fSMartin Matuska * the format handler might have reset the size field to zero 997caf54c4fSMartin Matuska * to inform us that the archive body won't get stored. In 998caf54c4fSMartin Matuska * that case, just skip the write. 999caf54c4fSMartin Matuska */ 1000caf54c4fSMartin Matuska if (e >= ARCHIVE_WARN && fd >= 0 && archive_entry_size(entry) > 0) { 1001*6c95142eSMartin Matuska if (write_file_data(bsdtar, a, entry, fd, align)) 1002caf54c4fSMartin Matuska exit(1); 1003caf54c4fSMartin Matuska } 1004caf54c4fSMartin Matuska 1005caf54c4fSMartin Matuska /* 1006caf54c4fSMartin Matuska * If we opened a file, close it now even if there was an error 1007caf54c4fSMartin Matuska * which made us decide not to write the archive body. 1008caf54c4fSMartin Matuska */ 1009caf54c4fSMartin Matuska if (fd >= 0) 1010caf54c4fSMartin Matuska close(fd); 1011caf54c4fSMartin Matuska } 1012caf54c4fSMartin Matuska 1013caf54c4fSMartin Matuska static void 1014caf54c4fSMartin Matuska report_write(struct bsdtar *bsdtar, struct archive *a, 1015caf54c4fSMartin Matuska struct archive_entry *entry, int64_t progress) 1016caf54c4fSMartin Matuska { 1017caf54c4fSMartin Matuska uint64_t comp, uncomp; 1018c5d360f8SMartin Matuska int compression; 1019c5d360f8SMartin Matuska 1020caf54c4fSMartin Matuska if (bsdtar->verbose) 1021caf54c4fSMartin Matuska fprintf(stderr, "\n"); 1022caf54c4fSMartin Matuska comp = archive_position_compressed(a); 1023caf54c4fSMartin Matuska uncomp = archive_position_uncompressed(a); 1024caf54c4fSMartin Matuska fprintf(stderr, "In: %d files, %s bytes;", 1025caf54c4fSMartin Matuska archive_file_count(a), tar_i64toa(uncomp)); 1026c5d360f8SMartin Matuska if (comp > uncomp) 1027c5d360f8SMartin Matuska compression = 0; 1028c5d360f8SMartin Matuska else 1029c5d360f8SMartin Matuska compression = (int)((uncomp - comp) * 100 / uncomp); 1030caf54c4fSMartin Matuska fprintf(stderr, 1031caf54c4fSMartin Matuska " Out: %s bytes, compression %d%%\n", 1032c5d360f8SMartin Matuska tar_i64toa(comp), compression); 1033caf54c4fSMartin Matuska /* Can't have two calls to tar_i64toa() pending, so split the output. */ 1034caf54c4fSMartin Matuska safe_fprintf(stderr, "Current: %s (%s", 1035caf54c4fSMartin Matuska archive_entry_pathname(entry), 1036caf54c4fSMartin Matuska tar_i64toa(progress)); 1037caf54c4fSMartin Matuska fprintf(stderr, "/%s bytes)\n", 1038caf54c4fSMartin Matuska tar_i64toa(archive_entry_size(entry))); 1039caf54c4fSMartin Matuska } 1040caf54c4fSMartin Matuska 1041caf54c4fSMartin Matuska 1042caf54c4fSMartin Matuska /* Helper function to copy file to archive. */ 1043caf54c4fSMartin Matuska static int 1044caf54c4fSMartin Matuska write_file_data(struct bsdtar *bsdtar, struct archive *a, 1045*6c95142eSMartin Matuska struct archive_entry *entry, int fd, size_t align) 1046caf54c4fSMartin Matuska { 1047caf54c4fSMartin Matuska ssize_t bytes_read; 1048caf54c4fSMartin Matuska ssize_t bytes_written; 1049caf54c4fSMartin Matuska int64_t progress = 0; 1050*6c95142eSMartin Matuska size_t buff_size; 1051*6c95142eSMartin Matuska char *buff = bsdtar->buff; 1052caf54c4fSMartin Matuska 1053*6c95142eSMartin Matuska /* Round 'buff' up to the next multiple of 'align' and reduce 1054*6c95142eSMartin Matuska * 'buff_size' accordingly. */ 1055*6c95142eSMartin Matuska buff = (char *)((((uintptr_t)buff + align - 1) / align) * align); 1056*6c95142eSMartin Matuska buff_size = bsdtar->buff + bsdtar->buff_size - buff; 1057*6c95142eSMartin Matuska buff_size = (buff_size / align) * align; 1058*6c95142eSMartin Matuska 1059*6c95142eSMartin Matuska bytes_read = read(fd, buff, buff_size); 1060caf54c4fSMartin Matuska while (bytes_read > 0) { 1061caf54c4fSMartin Matuska if (need_report()) 1062caf54c4fSMartin Matuska report_write(bsdtar, a, entry, progress); 1063caf54c4fSMartin Matuska 1064*6c95142eSMartin Matuska bytes_written = archive_write_data(a, buff, bytes_read); 1065caf54c4fSMartin Matuska if (bytes_written < 0) { 1066caf54c4fSMartin Matuska /* Write failed; this is bad */ 1067caf54c4fSMartin Matuska lafe_warnc(0, "%s", archive_error_string(a)); 1068caf54c4fSMartin Matuska return (-1); 1069caf54c4fSMartin Matuska } 1070caf54c4fSMartin Matuska if (bytes_written < bytes_read) { 1071caf54c4fSMartin Matuska /* Write was truncated; warn but continue. */ 1072caf54c4fSMartin Matuska lafe_warnc(0, 1073caf54c4fSMartin Matuska "%s: Truncated write; file may have grown while being archived.", 1074caf54c4fSMartin Matuska archive_entry_pathname(entry)); 1075caf54c4fSMartin Matuska return (0); 1076caf54c4fSMartin Matuska } 1077caf54c4fSMartin Matuska progress += bytes_written; 1078*6c95142eSMartin Matuska bytes_read = read(fd, buff, buff_size); 1079caf54c4fSMartin Matuska } 1080c5d360f8SMartin Matuska if (bytes_read < 0) { 1081c5d360f8SMartin Matuska lafe_warnc(errno, 1082c5d360f8SMartin Matuska "%s: Read error", 1083c5d360f8SMartin Matuska archive_entry_pathname(entry)); 1084c5d360f8SMartin Matuska bsdtar->return_value = 1; 1085c5d360f8SMartin Matuska } 1086caf54c4fSMartin Matuska return 0; 1087caf54c4fSMartin Matuska } 1088caf54c4fSMartin Matuska 1089caf54c4fSMartin Matuska /* 1090caf54c4fSMartin Matuska * Test if the specified file is new enough to include in the archive. 1091caf54c4fSMartin Matuska */ 1092caf54c4fSMartin Matuska static int 1093caf54c4fSMartin Matuska new_enough(struct bsdtar *bsdtar, const char *path, const struct stat *st) 1094caf54c4fSMartin Matuska { 1095caf54c4fSMartin Matuska struct archive_dir_entry *p; 1096caf54c4fSMartin Matuska 1097caf54c4fSMartin Matuska /* 1098caf54c4fSMartin Matuska * If this file/dir is excluded by a time comparison, skip it. 1099caf54c4fSMartin Matuska */ 1100*6c95142eSMartin Matuska if (bsdtar->newer_ctime_filter) { 1101caf54c4fSMartin Matuska if (st->st_ctime < bsdtar->newer_ctime_sec) 1102caf54c4fSMartin Matuska return (0); /* Too old, skip it. */ 1103caf54c4fSMartin Matuska if (st->st_ctime == bsdtar->newer_ctime_sec 1104caf54c4fSMartin Matuska && ARCHIVE_STAT_CTIME_NANOS(st) 1105caf54c4fSMartin Matuska <= bsdtar->newer_ctime_nsec) 1106caf54c4fSMartin Matuska return (0); /* Too old, skip it. */ 1107caf54c4fSMartin Matuska } 1108*6c95142eSMartin Matuska if (bsdtar->newer_mtime_filter) { 1109caf54c4fSMartin Matuska if (st->st_mtime < bsdtar->newer_mtime_sec) 1110caf54c4fSMartin Matuska return (0); /* Too old, skip it. */ 1111caf54c4fSMartin Matuska if (st->st_mtime == bsdtar->newer_mtime_sec 1112caf54c4fSMartin Matuska && ARCHIVE_STAT_MTIME_NANOS(st) 1113caf54c4fSMartin Matuska <= bsdtar->newer_mtime_nsec) 1114caf54c4fSMartin Matuska return (0); /* Too old, skip it. */ 1115caf54c4fSMartin Matuska } 1116caf54c4fSMartin Matuska 1117caf54c4fSMartin Matuska /* 1118caf54c4fSMartin Matuska * In -u mode, we only write an entry if it's newer than 1119caf54c4fSMartin Matuska * what was already in the archive. 1120caf54c4fSMartin Matuska */ 1121caf54c4fSMartin Matuska if (bsdtar->archive_dir != NULL && 1122caf54c4fSMartin Matuska bsdtar->archive_dir->head != NULL) { 1123caf54c4fSMartin Matuska for (p = bsdtar->archive_dir->head; p != NULL; p = p->next) { 1124caf54c4fSMartin Matuska if (pathcmp(path, p->name)==0) 1125caf54c4fSMartin Matuska return (p->mtime_sec < st->st_mtime || 1126caf54c4fSMartin Matuska (p->mtime_sec == st->st_mtime && 1127caf54c4fSMartin Matuska p->mtime_nsec 1128caf54c4fSMartin Matuska < ARCHIVE_STAT_MTIME_NANOS(st))); 1129caf54c4fSMartin Matuska } 1130caf54c4fSMartin Matuska } 1131caf54c4fSMartin Matuska 1132caf54c4fSMartin Matuska /* If the file wasn't rejected, include it. */ 1133caf54c4fSMartin Matuska return (1); 1134caf54c4fSMartin Matuska } 1135caf54c4fSMartin Matuska 1136caf54c4fSMartin Matuska /* 1137caf54c4fSMartin Matuska * Add an entry to the dir list for 'u' mode. 1138caf54c4fSMartin Matuska * 1139caf54c4fSMartin Matuska * XXX TODO: Make this fast. 1140caf54c4fSMartin Matuska */ 1141caf54c4fSMartin Matuska static void 1142caf54c4fSMartin Matuska add_dir_list(struct bsdtar *bsdtar, const char *path, 1143caf54c4fSMartin Matuska time_t mtime_sec, int mtime_nsec) 1144caf54c4fSMartin Matuska { 1145caf54c4fSMartin Matuska struct archive_dir_entry *p; 1146caf54c4fSMartin Matuska 1147caf54c4fSMartin Matuska /* 1148caf54c4fSMartin Matuska * Search entire list to see if this file has appeared before. 1149caf54c4fSMartin Matuska * If it has, override the timestamp data. 1150caf54c4fSMartin Matuska */ 1151caf54c4fSMartin Matuska p = bsdtar->archive_dir->head; 1152caf54c4fSMartin Matuska while (p != NULL) { 1153caf54c4fSMartin Matuska if (strcmp(path, p->name)==0) { 1154caf54c4fSMartin Matuska p->mtime_sec = mtime_sec; 1155caf54c4fSMartin Matuska p->mtime_nsec = mtime_nsec; 1156caf54c4fSMartin Matuska return; 1157caf54c4fSMartin Matuska } 1158caf54c4fSMartin Matuska p = p->next; 1159caf54c4fSMartin Matuska } 1160caf54c4fSMartin Matuska 1161caf54c4fSMartin Matuska p = malloc(sizeof(*p)); 1162caf54c4fSMartin Matuska if (p == NULL) 1163caf54c4fSMartin Matuska lafe_errc(1, ENOMEM, "Can't read archive directory"); 1164caf54c4fSMartin Matuska 1165caf54c4fSMartin Matuska p->name = strdup(path); 1166caf54c4fSMartin Matuska if (p->name == NULL) 1167caf54c4fSMartin Matuska lafe_errc(1, ENOMEM, "Can't read archive directory"); 1168caf54c4fSMartin Matuska p->mtime_sec = mtime_sec; 1169caf54c4fSMartin Matuska p->mtime_nsec = mtime_nsec; 1170caf54c4fSMartin Matuska p->next = NULL; 1171caf54c4fSMartin Matuska if (bsdtar->archive_dir->tail == NULL) { 1172caf54c4fSMartin Matuska bsdtar->archive_dir->head = bsdtar->archive_dir->tail = p; 1173caf54c4fSMartin Matuska } else { 1174caf54c4fSMartin Matuska bsdtar->archive_dir->tail->next = p; 1175caf54c4fSMartin Matuska bsdtar->archive_dir->tail = p; 1176caf54c4fSMartin Matuska } 1177caf54c4fSMartin Matuska } 1178caf54c4fSMartin Matuska 1179caf54c4fSMartin Matuska static void 1180caf54c4fSMartin Matuska test_for_append(struct bsdtar *bsdtar) 1181caf54c4fSMartin Matuska { 1182caf54c4fSMartin Matuska struct stat s; 1183caf54c4fSMartin Matuska 1184caf54c4fSMartin Matuska if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) 1185caf54c4fSMartin Matuska lafe_errc(1, 0, "no files or directories specified"); 1186caf54c4fSMartin Matuska if (bsdtar->filename == NULL) 1187caf54c4fSMartin Matuska lafe_errc(1, 0, "Cannot append to stdout."); 1188caf54c4fSMartin Matuska 1189caf54c4fSMartin Matuska if (bsdtar->create_compression != 0) 1190caf54c4fSMartin Matuska lafe_errc(1, 0, 1191caf54c4fSMartin Matuska "Cannot append to %s with compression", bsdtar->filename); 1192caf54c4fSMartin Matuska 1193caf54c4fSMartin Matuska if (stat(bsdtar->filename, &s) != 0) 1194caf54c4fSMartin Matuska return; 1195caf54c4fSMartin Matuska 1196caf54c4fSMartin Matuska if (!S_ISREG(s.st_mode) && !S_ISBLK(s.st_mode)) 1197caf54c4fSMartin Matuska lafe_errc(1, 0, 1198caf54c4fSMartin Matuska "Cannot append to %s: not a regular file.", 1199caf54c4fSMartin Matuska bsdtar->filename); 1200caf54c4fSMartin Matuska 1201caf54c4fSMartin Matuska /* Is this an appropriate check here on Windows? */ 1202caf54c4fSMartin Matuska /* 1203caf54c4fSMartin Matuska if (GetFileType(handle) != FILE_TYPE_DISK) 1204caf54c4fSMartin Matuska lafe_errc(1, 0, "Cannot append"); 1205caf54c4fSMartin Matuska */ 1206caf54c4fSMartin Matuska 1207caf54c4fSMartin Matuska } 1208