int lafe_include_from_file(struct lafe_matching **matching, const char *pathname, int nullSeparator) { struct lafe_line_reader *lr; const char *p; int ret = 0; lr = lafe_line_reader(pathname, nullSeparator); while ((p = lafe_line_reader_next(lr)) != NULL) { if (lafe_include(matching, p) != 0) ret = -1; } lafe_line_reader_free(lr); return (ret); }
int main(int argc, char **argv) { struct bsdtar *bsdtar, bsdtar_storage; int opt, t; char option_o; char possible_help_request; char buff[16]; time_t now; /* * Use a pointer for consistency, but stack-allocated storage * for ease of cleanup. */ _bsdtar = bsdtar = &bsdtar_storage; memset(bsdtar, 0, sizeof(*bsdtar)); bsdtar->fd = -1; /* Mark as "unused" */ option_o = 0; #if defined(SIGINFO) || defined(SIGUSR1) { /* Catch SIGINFO and SIGUSR1, if they exist. */ struct sigaction sa; sa.sa_handler = siginfo_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; #ifdef SIGINFO if (sigaction(SIGINFO, &sa, NULL)) lafe_errc(1, errno, "sigaction(SIGINFO) failed"); #endif #ifdef SIGUSR1 /* ... and treat SIGUSR1 the same way as SIGINFO. */ if (sigaction(SIGUSR1, &sa, NULL)) lafe_errc(1, errno, "sigaction(SIGUSR1) failed"); #endif } #endif /* Need lafe_progname before calling lafe_warnc. */ if (*argv == NULL) lafe_progname = "bsdtar"; else { #if defined(_WIN32) && !defined(__CYGWIN__) lafe_progname = strrchr(*argv, '\\'); #else lafe_progname = strrchr(*argv, '/'); #endif if (lafe_progname != NULL) lafe_progname++; else lafe_progname = *argv; } time(&now); #if HAVE_SETLOCALE if (setlocale(LC_ALL, "") == NULL) lafe_warnc(0, "Failed to set default locale"); #endif #if defined(HAVE_NL_LANGINFO) && defined(HAVE_D_MD_ORDER) bsdtar->day_first = (*nl_langinfo(D_MD_ORDER) == 'd'); #endif possible_help_request = 0; /* Look up uid of current user for future reference */ bsdtar->user_uid = geteuid(); /* Default: open tape drive. */ bsdtar->filename = getenv("TAPE"); if (bsdtar->filename == NULL) bsdtar->filename = _PATH_DEFTAPE; /* Default: preserve mod time on extract */ bsdtar->extract_flags = ARCHIVE_EXTRACT_TIME; /* Default: Perform basic security checks. */ bsdtar->extract_flags |= SECURITY; #ifndef _WIN32 /* On POSIX systems, assume --same-owner and -p when run by * the root user. This doesn't make any sense on Windows. */ if (bsdtar->user_uid == 0) { /* --same-owner */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER; /* -p */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; } #endif bsdtar->argv = argv; bsdtar->argc = argc; /* * Comments following each option indicate where that option * originated: SUSv2, POSIX, GNU tar, star, etc. If there's * no such comment, then I don't know of anyone else who * implements that option. */ while ((opt = bsdtar_getopt(bsdtar)) != -1) { switch (opt) { case 'B': /* GNU tar */ /* libarchive doesn't need this; just ignore it. */ break; case 'b': /* SUSv2 */ t = atoi(bsdtar->optarg); if (t <= 0 || t > 1024) lafe_errc(1, 0, "Argument to -b is out of range (1..1024)"); bsdtar->bytes_per_block = 512 * t; break; case 'C': /* GNU tar */ set_chdir(bsdtar, bsdtar->optarg); break; case 'c': /* SUSv2 */ set_mode(bsdtar, opt); break; case OPTION_CHECK_LINKS: /* GNU tar */ bsdtar->option_warn_links = 1; break; case OPTION_CHROOT: /* NetBSD */ bsdtar->option_chroot = 1; break; case OPTION_EXCLUDE: /* GNU tar */ if (lafe_exclude(&bsdtar->matching, bsdtar->optarg)) lafe_errc(1, 0, "Couldn't exclude %s\n", bsdtar->optarg); break; case OPTION_FORMAT: /* GNU tar, others */ bsdtar->create_format = bsdtar->optarg; break; case OPTION_OPTIONS: bsdtar->option_options = bsdtar->optarg; break; case 'f': /* SUSv2 */ bsdtar->filename = bsdtar->optarg; if (strcmp(bsdtar->filename, "-") == 0) bsdtar->filename = NULL; break; case 'H': /* BSD convention */ bsdtar->symlink_mode = 'H'; break; case 'h': /* Linux Standards Base, gtar; synonym for -L */ bsdtar->symlink_mode = 'L'; /* Hack: -h by itself is the "help" command. */ possible_help_request = 1; break; case OPTION_HELP: /* GNU tar, others */ long_help(); exit(0); break; case 'I': /* GNU tar */ /* * TODO: Allow 'names' to come from an archive, * not just a text file. Design a good UI for * allowing names and mode/owner to be read * from an archive, with contents coming from * disk. This can be used to "refresh" an * archive or to design archives with special * permissions without having to create those * permissions on disk. */ bsdtar->names_from_file = bsdtar->optarg; break; case OPTION_INCLUDE: /* * Noone else has the @archive extension, so * noone else needs this to filter entries * when transforming archives. */ if (lafe_include(&bsdtar->matching, bsdtar->optarg)) lafe_errc(1, 0, "Failed to add %s to inclusion list", bsdtar->optarg); break; case 'j': /* GNU tar */ if (bsdtar->create_compression != '\0') lafe_errc(1, 0, "Can't specify both -%c and -%c", opt, bsdtar->create_compression); bsdtar->create_compression = opt; break; case 'J': /* GNU tar 1.21 and later */ if (bsdtar->create_compression != '\0') lafe_errc(1, 0, "Can't specify both -%c and -%c", opt, bsdtar->create_compression); bsdtar->create_compression = opt; break; case 'k': /* GNU tar */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE; break; case OPTION_KEEP_NEWER_FILES: /* GNU tar */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; break; case 'L': /* BSD convention */ bsdtar->symlink_mode = 'L'; break; case 'l': /* SUSv2 and GNU tar beginning with 1.16 */ /* GNU tar 1.13 used -l for --one-file-system */ bsdtar->option_warn_links = 1; break; case OPTION_LZMA: if (bsdtar->create_compression != '\0') lafe_errc(1, 0, "Can't specify both -%c and -%c", opt, bsdtar->create_compression); bsdtar->create_compression = opt; break; case 'm': /* SUSv2 */ bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME; break; case 'n': /* GNU tar */ bsdtar->option_no_subdirs = 1; break; /* * Selecting files by time: * --newer-?time='date' Only files newer than 'date' * --newer-?time-than='file' Only files newer than time * on specified file (useful for incremental backups) * TODO: Add corresponding "older" options to reverse these. */ case OPTION_NEWER_CTIME: /* GNU tar */ bsdtar->newer_ctime_sec = get_date(now, bsdtar->optarg); break; case OPTION_NEWER_CTIME_THAN: { struct stat st; if (stat(bsdtar->optarg, &st) != 0) lafe_errc(1, 0, "Can't open file %s", bsdtar->optarg); bsdtar->newer_ctime_sec = st.st_ctime; bsdtar->newer_ctime_nsec = ARCHIVE_STAT_CTIME_NANOS(&st); } break; case OPTION_NEWER_MTIME: /* GNU tar */ bsdtar->newer_mtime_sec = get_date(now, bsdtar->optarg); break; case OPTION_NEWER_MTIME_THAN: { struct stat st; if (stat(bsdtar->optarg, &st) != 0) lafe_errc(1, 0, "Can't open file %s", bsdtar->optarg); bsdtar->newer_mtime_sec = st.st_mtime; bsdtar->newer_mtime_nsec = ARCHIVE_STAT_MTIME_NANOS(&st); } break; case OPTION_NODUMP: /* star */ bsdtar->option_honor_nodump = 1; break; case OPTION_NO_SAME_OWNER: /* GNU tar */ bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; break; case OPTION_NO_SAME_PERMISSIONS: /* GNU tar */ bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_PERM; bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_ACL; bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_XATTR; bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_FFLAGS; break; case OPTION_NULL: /* GNU tar */ bsdtar->option_null++; break; case OPTION_NUMERIC_OWNER: /* GNU tar */ bsdtar->option_numeric_owner++; break; case 'O': /* GNU tar */ bsdtar->option_stdout = 1; break; case 'o': /* SUSv2 and GNU conflict here, but not fatally */ option_o = 1; /* Record it and resolve it later. */ break; case OPTION_ONE_FILE_SYSTEM: /* GNU tar */ bsdtar->option_dont_traverse_mounts = 1; break; #if 0 /* * The common BSD -P option is not necessary, since * our default is to archive symlinks, not follow * them. This is convenient, as -P conflicts with GNU * tar anyway. */ case 'P': /* BSD convention */ /* Default behavior, no option necessary. */ break; #endif case 'P': /* GNU tar */ bsdtar->extract_flags &= ~SECURITY; bsdtar->option_absolute_paths = 1; break; case 'p': /* GNU tar, star */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; break; case OPTION_POSIX: /* GNU tar */ bsdtar->create_format = "pax"; break; case 'q': /* FreeBSD GNU tar --fast-read, NetBSD -q */ bsdtar->option_fast_read = 1; break; case 'r': /* SUSv2 */ set_mode(bsdtar, opt); break; case 'S': /* NetBSD pax-as-tar */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_SPARSE; break; case 's': /* NetBSD pax-as-tar */ #if HAVE_REGEX_H add_substitution(bsdtar, bsdtar->optarg); #else lafe_warnc(0, "-s is not supported by this version of bsdtar"); usage(); #endif break; case OPTION_SAME_OWNER: /* GNU tar */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER; break; case OPTION_STRIP_COMPONENTS: /* GNU tar 1.15 */ bsdtar->strip_components = atoi(bsdtar->optarg); break; case 'T': /* GNU tar */ bsdtar->names_from_file = bsdtar->optarg; break; case 't': /* SUSv2 */ set_mode(bsdtar, opt); bsdtar->verbose++; break; case OPTION_TOTALS: /* GNU tar */ bsdtar->option_totals++; break; case 'U': /* GNU tar */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_UNLINK; bsdtar->option_unlink_first = 1; break; case 'u': /* SUSv2 */ set_mode(bsdtar, opt); break; case 'v': /* SUSv2 */ bsdtar->verbose++; break; case OPTION_VERSION: /* GNU convention */ version(); break; #if 0 /* * The -W longopt feature is handled inside of * bsdtar_getopt(), so -W is not available here. */ case 'W': /* Obscure GNU convention. */ break; #endif case 'w': /* SUSv2 */ bsdtar->option_interactive = 1; break; case 'X': /* GNU tar */ if (lafe_exclude_from_file(&bsdtar->matching, bsdtar->optarg)) lafe_errc(1, 0, "failed to process exclusions from file %s", bsdtar->optarg); break; case 'x': /* SUSv2 */ set_mode(bsdtar, opt); break; case 'y': /* FreeBSD version of GNU tar */ if (bsdtar->create_compression != '\0') lafe_errc(1, 0, "Can't specify both -%c and -%c", opt, bsdtar->create_compression); bsdtar->create_compression = opt; break; case 'Z': /* GNU tar */ if (bsdtar->create_compression != '\0') lafe_errc(1, 0, "Can't specify both -%c and -%c", opt, bsdtar->create_compression); bsdtar->create_compression = opt; break; case 'z': /* GNU tar, star, many others */ if (bsdtar->create_compression != '\0') lafe_errc(1, 0, "Can't specify both -%c and -%c", opt, bsdtar->create_compression); bsdtar->create_compression = opt; break; case OPTION_USE_COMPRESS_PROGRAM: bsdtar->compress_program = bsdtar->optarg; break; default: usage(); } } /* * Sanity-check options. */ /* If no "real" mode was specified, treat -h as --help. */ if ((bsdtar->mode == '\0') && possible_help_request) { long_help(); exit(0); } /* Otherwise, a mode is required. */ if (bsdtar->mode == '\0') lafe_errc(1, 0, "Must specify one of -c, -r, -t, -u, -x"); /* Check boolean options only permitted in certain modes. */ if (bsdtar->option_dont_traverse_mounts) only_mode(bsdtar, "--one-file-system", "cru"); if (bsdtar->option_fast_read) only_mode(bsdtar, "--fast-read", "xt"); if (bsdtar->option_honor_nodump) only_mode(bsdtar, "--nodump", "cru"); if (option_o > 0) { switch (bsdtar->mode) { case 'c': /* * In GNU tar, -o means "old format." The * "ustar" format is the closest thing * supported by libarchive. */ bsdtar->create_format = "ustar"; /* TODO: bsdtar->create_format = "v7"; */ break; case 'x': /* POSIX-compatible behavior. */ bsdtar->option_no_owner = 1; bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; break; default: only_mode(bsdtar, "-o", "xc"); break; } } if (bsdtar->option_no_subdirs) only_mode(bsdtar, "-n", "cru"); if (bsdtar->option_stdout) only_mode(bsdtar, "-O", "xt"); if (bsdtar->option_unlink_first) only_mode(bsdtar, "-U", "x"); if (bsdtar->option_warn_links) only_mode(bsdtar, "--check-links", "cr"); /* Check other parameters only permitted in certain modes. */ if (bsdtar->create_compression != '\0') { strcpy(buff, "-?"); buff[1] = bsdtar->create_compression; only_mode(bsdtar, buff, "cxt"); } if (bsdtar->create_format != NULL) only_mode(bsdtar, "--format", "cru"); if (bsdtar->symlink_mode != '\0') { strcpy(buff, "-?"); buff[1] = bsdtar->symlink_mode; only_mode(bsdtar, buff, "cru"); } if (bsdtar->strip_components != 0) only_mode(bsdtar, "--strip-components", "xt"); switch(bsdtar->mode) { case 'c': tar_mode_c(bsdtar); break; case 'r': tar_mode_r(bsdtar); break; case 't': tar_mode_t(bsdtar); break; case 'u': tar_mode_u(bsdtar); break; case 'x': tar_mode_x(bsdtar); break; } lafe_cleanup_exclusions(&bsdtar->matching); #if HAVE_REGEX_H cleanup_substitution(bsdtar); #endif if (bsdtar->return_value != 0) lafe_warnc(0, "Error exit delayed from previous errors."); return (bsdtar->return_value); }
int main(int argc, char *argv[]) { static char buff[16384]; struct cpio _cpio; /* Allocated on stack. */ struct cpio *cpio; const char *errmsg; int uid, gid; int opt; cpio = &_cpio; memset(cpio, 0, sizeof(*cpio)); cpio->buff = buff; cpio->buff_size = sizeof(buff); /* Need lafe_progname before calling lafe_warnc. */ if (*argv == NULL) lafe_progname = "bsdcpio"; else { #if defined(_WIN32) && !defined(__CYGWIN__) lafe_progname = strrchr(*argv, '\\'); #else lafe_progname = strrchr(*argv, '/'); #endif if (lafe_progname != NULL) lafe_progname++; else lafe_progname = *argv; } cpio->uid_override = -1; cpio->gid_override = -1; cpio->argv = argv; cpio->argc = argc; cpio->mode = '\0'; cpio->verbose = 0; cpio->compress = '\0'; cpio->extract_flags = ARCHIVE_EXTRACT_NO_AUTODIR; cpio->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS; cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT; cpio->extract_flags |= ARCHIVE_EXTRACT_PERM; cpio->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; cpio->extract_flags |= ARCHIVE_EXTRACT_ACL; #if !defined(_WIN32) && !defined(__CYGWIN__) if (geteuid() == 0) cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; #endif cpio->bytes_per_block = 512; cpio->filename = NULL; while ((opt = cpio_getopt(cpio)) != -1) { switch (opt) { case '0': /* GNU convention: --null, -0 */ cpio->option_null = 1; break; case 'A': /* NetBSD/OpenBSD */ cpio->option_append = 1; break; case 'a': /* POSIX 1997 */ cpio->option_atime_restore = 1; break; case 'B': /* POSIX 1997 */ cpio->bytes_per_block = 5120; break; case 'C': /* NetBSD/OpenBSD */ cpio->bytes_per_block = atoi(cpio->optarg); if (cpio->bytes_per_block <= 0) lafe_errc(1, 0, "Invalid blocksize %s", cpio->optarg); break; case 'c': /* POSIX 1997 */ cpio->format = "odc"; break; case 'd': /* POSIX 1997 */ cpio->extract_flags &= ~ARCHIVE_EXTRACT_NO_AUTODIR; break; case 'E': /* NetBSD/OpenBSD */ lafe_include_from_file(&cpio->matching, cpio->optarg, cpio->option_null); break; case 'F': /* NetBSD/OpenBSD/GNU cpio */ cpio->filename = cpio->optarg; break; case 'f': /* POSIX 1997 */ lafe_exclude(&cpio->matching, cpio->optarg); break; case 'H': /* GNU cpio (also --format) */ cpio->format = cpio->optarg; break; case 'h': long_help(); break; case 'I': /* NetBSD/OpenBSD */ cpio->filename = cpio->optarg; break; case 'i': /* POSIX 1997 */ if (cpio->mode != '\0') lafe_errc(1, 0, "Cannot use both -i and -%c", cpio->mode); cpio->mode = opt; break; case 'J': /* GNU tar, others */ cpio->compress = opt; break; case 'j': /* GNU tar, others */ cpio->compress = opt; break; case OPTION_INSECURE: cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_SYMLINKS; cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; break; case 'L': /* GNU cpio */ cpio->option_follow_links = 1; break; case 'l': /* POSIX 1997 */ cpio->option_link = 1; break; case OPTION_LZMA: /* GNU tar, others */ cpio->compress = opt; break; case 'm': /* POSIX 1997 */ cpio->extract_flags |= ARCHIVE_EXTRACT_TIME; break; case 'n': /* GNU cpio */ cpio->option_numeric_uid_gid = 1; break; case OPTION_NO_PRESERVE_OWNER: /* GNU cpio */ cpio->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; break; case 'O': /* GNU cpio */ cpio->filename = cpio->optarg; break; case 'o': /* POSIX 1997 */ if (cpio->mode != '\0') lafe_errc(1, 0, "Cannot use both -o and -%c", cpio->mode); cpio->mode = opt; break; case 'p': /* POSIX 1997 */ if (cpio->mode != '\0') lafe_errc(1, 0, "Cannot use both -p and -%c", cpio->mode); cpio->mode = opt; cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; break; case OPTION_PRESERVE_OWNER: cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; break; case OPTION_QUIET: /* GNU cpio */ cpio->quiet = 1; break; case 'R': /* GNU cpio, also --owner */ errmsg = owner_parse(cpio->optarg, &uid, &gid); if (errmsg) { lafe_warnc(-1, "%s", errmsg); usage(); } if (uid != -1) cpio->uid_override = uid; if (gid != -1) cpio->gid_override = gid; break; case 'r': /* POSIX 1997 */ cpio->option_rename = 1; break; case 't': /* POSIX 1997 */ cpio->option_list = 1; break; case 'u': /* POSIX 1997 */ cpio->extract_flags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; break; case 'v': /* POSIX 1997 */ cpio->verbose++; break; case OPTION_VERSION: /* GNU convention */ version(); break; #if 0 /* * cpio_getopt() handles -W specially, so it's not * available here. */ case 'W': /* Obscure, but useful GNU convention. */ break; #endif case 'y': /* tar convention */ cpio->compress = opt; break; case 'Z': /* tar convention */ cpio->compress = opt; break; case 'z': /* tar convention */ cpio->compress = opt; break; default: usage(); } } /* * Sanity-check args, error out on nonsensical combinations. */ /* -t implies -i if no mode was specified. */ if (cpio->option_list && cpio->mode == '\0') cpio->mode = 'i'; /* -t requires -i */ if (cpio->option_list && cpio->mode != 'i') lafe_errc(1, 0, "Option -t requires -i"); /* -n requires -it */ if (cpio->option_numeric_uid_gid && !cpio->option_list) lafe_errc(1, 0, "Option -n requires -it"); /* Can only specify format when writing */ if (cpio->format != NULL && cpio->mode != 'o') lafe_errc(1, 0, "Option --format requires -o"); /* -l requires -p */ if (cpio->option_link && cpio->mode != 'p') lafe_errc(1, 0, "Option -l requires -p"); /* TODO: Flag other nonsensical combinations. */ switch (cpio->mode) { case 'o': /* TODO: Implement old binary format in libarchive, use that here. */ if (cpio->format == NULL) cpio->format = "odc"; /* Default format */ mode_out(cpio); break; case 'i': while (*cpio->argv != NULL) { lafe_include(&cpio->matching, *cpio->argv); --cpio->argc; ++cpio->argv; } if (cpio->option_list) mode_list(cpio); else mode_in(cpio); break; case 'p': if (*cpio->argv == NULL || **cpio->argv == '\0') lafe_errc(1, 0, "-p mode requires a target directory"); mode_pass(cpio, *cpio->argv); break; default: lafe_errc(1, 0, "Must specify at least one of -i, -o, or -p"); } free_cache(cpio->gname_cache); free_cache(cpio->uname_cache); return (cpio->return_value); }
/* * Handle 'x' and 't' modes. */ static void read_archive(struct bsdtar *bsdtar, char mode) { struct progress_data progress_data; FILE *out; struct archive *a; struct archive_entry *entry; const struct stat *st; int r; while (*bsdtar->argv) { lafe_include(&bsdtar->matching, *bsdtar->argv); bsdtar->argv++; } if (bsdtar->names_from_file != NULL) lafe_include_from_file(&bsdtar->matching, bsdtar->names_from_file, bsdtar->option_null); a = archive_read_new(); if (bsdtar->compress_program != NULL) archive_read_support_compression_program(a, bsdtar->compress_program); else archive_read_support_compression_all(a); archive_read_support_format_all(a); if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options)) lafe_errc(1, 0, "%s", archive_error_string(a)); if (archive_read_open_file(a, bsdtar->filename, bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : DEFAULT_BYTES_PER_BLOCK)) lafe_errc(1, 0, "Error opening archive: %s", archive_error_string(a)); do_chdir(bsdtar); if (mode == 'x') { /* Set an extract callback so that we can handle SIGINFO. */ progress_data.bsdtar = bsdtar; progress_data.archive = a; archive_read_extract_set_progress_callback(a, progress_func, &progress_data); } if (mode == 'x' && bsdtar->option_chroot) { #if HAVE_CHROOT if (chroot(".") != 0) lafe_errc(1, errno, "Can't chroot to \".\""); #else lafe_errc(1, 0, "chroot isn't supported on this platform"); #endif } for (;;) { /* Support --fast-read option */ if (bsdtar->option_fast_read && lafe_unmatched_inclusions(bsdtar->matching) == 0) break; r = archive_read_next_header(a, &entry); progress_data.entry = entry; if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) lafe_warnc(0, "%s", archive_error_string(a)); if (r <= ARCHIVE_WARN) bsdtar->return_value = 1; if (r == ARCHIVE_RETRY) { /* Retryable error: try again */ lafe_warnc(0, "Retrying..."); continue; } if (r == ARCHIVE_FATAL) break; if (bsdtar->uid >= 0) { archive_entry_set_uid(entry, bsdtar->uid); archive_entry_set_uname(entry, NULL); } if (bsdtar->gid >= 0) { archive_entry_set_gid(entry, bsdtar->gid); archive_entry_set_gname(entry, NULL); } if (bsdtar->uname) archive_entry_set_uname(entry, bsdtar->uname); if (bsdtar->gname) archive_entry_set_gname(entry, bsdtar->gname); /* * Exclude entries that are too old. */ st = archive_entry_stat(entry); if (bsdtar->newer_ctime_sec > 0) { if (st->st_ctime < bsdtar->newer_ctime_sec) continue; /* Too old, skip it. */ if (st->st_ctime == bsdtar->newer_ctime_sec && ARCHIVE_STAT_CTIME_NANOS(st) <= bsdtar->newer_ctime_nsec) continue; /* Too old, skip it. */ } if (bsdtar->newer_mtime_sec > 0) { if (st->st_mtime < bsdtar->newer_mtime_sec) continue; /* Too old, skip it. */ if (st->st_mtime == bsdtar->newer_mtime_sec && ARCHIVE_STAT_MTIME_NANOS(st) <= bsdtar->newer_mtime_nsec) continue; /* Too old, skip it. */ } /* * Note that pattern exclusions are checked before * pathname rewrites are handled. This gives more * control over exclusions, since rewrites always lose * information. (For example, consider a rewrite * s/foo[0-9]/foo/. If we check exclusions after the * rewrite, there would be no way to exclude foo1/bar * while allowing foo2/bar.) */ if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry))) continue; /* Excluded by a pattern test. */ if (mode == 't') { /* Perversely, gtar uses -O to mean "send to stderr" * when used with -t. */ out = bsdtar->option_stdout ? stderr : stdout; /* * TODO: Provide some reasonable way to * preview rewrites. gtar always displays * the unedited path in -t output, which means * you cannot easily preview rewrites. */ if (bsdtar->verbose < 2) safe_fprintf(out, "%s", archive_entry_pathname(entry)); else list_item_verbose(bsdtar, out, entry); fflush(out); r = archive_read_data_skip(a); if (r == ARCHIVE_WARN) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); } if (r == ARCHIVE_RETRY) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); } if (r == ARCHIVE_FATAL) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); bsdtar->return_value = 1; break; } fprintf(out, "\n"); } else { /* Note: some rewrite failures prevent extraction. */ if (edit_pathname(bsdtar, entry)) continue; /* Excluded by a rewrite failure. */ if (bsdtar->option_interactive && !yes("extract '%s'", archive_entry_pathname(entry))) continue; /* * Format here is from SUSv2, including the * deferred '\n'. */ if (bsdtar->verbose) { safe_fprintf(stderr, "x %s", archive_entry_pathname(entry)); fflush(stderr); } // TODO siginfo_printinfo(bsdtar, 0); if (bsdtar->option_stdout) r = archive_read_data_into_fd(a, 1); else r = archive_read_extract(a, entry, bsdtar->extract_flags); if (r != ARCHIVE_OK) { if (!bsdtar->verbose) safe_fprintf(stderr, "%s", archive_entry_pathname(entry)); safe_fprintf(stderr, ": %s", archive_error_string(a)); if (!bsdtar->verbose) fprintf(stderr, "\n"); bsdtar->return_value = 1; } if (bsdtar->verbose) fprintf(stderr, "\n"); if (r == ARCHIVE_FATAL) break; } } r = archive_read_close(a); if (r != ARCHIVE_OK) lafe_warnc(0, "%s", archive_error_string(a)); if (r <= ARCHIVE_WARN) bsdtar->return_value = 1; if (bsdtar->verbose > 2) fprintf(stdout, "Archive Format: %s, Compression: %s\n", archive_format_name(a), archive_compression_name(a)); archive_read_finish(a); }