X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftar;a=blobdiff_plain;f=src%2Ftar.c;h=cd2849545a3ddf4ff8c6e3451a7181a7d5a78f69;hp=6d370441b96e5932198aeb4a6b6dbbe5ac371e29;hb=45ccda119355a1087450039a250359c1d0de0d08;hpb=1f9b376c90f50836b1ca2517cda0bfcab75ad8ae diff --git a/src/tar.c b/src/tar.c index 6d37044..cd28495 100644 --- a/src/tar.c +++ b/src/tar.c @@ -1,7 +1,7 @@ /* A tar (tape archiver) program. - Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, - 2001, 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc. + Copyright 1988, 1992-1997, 1999-2001, 2003-2007, 2012-2014 Free + Software Foundation, Inc. Written by John Gilmore, starting 1985-08-25. @@ -16,8 +16,7 @@ Public License for more details. You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + with this program. If not, see . */ #include @@ -67,6 +66,12 @@ # define DEFAULT_BLOCKING 20 #endif +/* Print a message if not all links are dumped */ +static int check_links_option; + +/* Number of allocated tape drive names. */ +static size_t allocated_archive_names; + /* Miscellaneous. */ @@ -74,11 +79,11 @@ static const char *stdin_used_by; /* Doesn't return if stdin already requested. */ -static void +void request_stdin (const char *option) { if (stdin_used_by) - USAGE_ERROR ((0, 0, _("Options `-%s' and `-%s' both want standard input"), + USAGE_ERROR ((0, 0, _("Options '-%s' and '-%s' both want standard input"), stdin_used_by, option)); stdin_used_by = option; @@ -247,7 +252,7 @@ tar_set_quoting_style (char *arg) return; } FATAL_ERROR ((0, 0, - _("Unknown quoting style `%s'. Try `%s --quoting-style=help' to get a list."), arg, program_invocation_short_name)); + _("Unknown quoting style '%s'. Try '%s --quoting-style=help' to get a list."), arg, program_invocation_short_name)); } @@ -255,7 +260,8 @@ tar_set_quoting_style (char *arg) enum { - ANCHORED_OPTION = CHAR_MAX + 1, + ACLS_OPTION = CHAR_MAX + 1, + ANCHORED_OPTION, ATIME_PRESERVE_OPTION, BACKUP_OPTION, CHECK_DEVICE_OPTION, @@ -280,6 +286,7 @@ enum IGNORE_COMMAND_ERROR_OPTION, IGNORE_FAILED_READ_OPTION, INDEX_FILE_OPTION, + KEEP_DIRECTORY_SYMLINK_OPTION, KEEP_NEWER_FILES_OPTION, LEVEL_OPTION, LZIP_OPTION, @@ -288,6 +295,7 @@ enum MODE_OPTION, MTIME_OPTION, NEWER_MTIME_OPTION, + NO_ACLS_OPTION, NO_ANCHORED_OPTION, NO_AUTO_COMPRESS_OPTION, NO_CHECK_DEVICE_OPTION, @@ -301,14 +309,17 @@ enum NO_SAME_OWNER_OPTION, NO_SAME_PERMISSIONS_OPTION, NO_SEEK_OPTION, + NO_SELINUX_CONTEXT_OPTION, NO_UNQUOTE_OPTION, NO_WILDCARDS_MATCH_SLASH_OPTION, NO_WILDCARDS_OPTION, + NO_XATTR_OPTION, NULL_OPTION, NUMERIC_OWNER_OPTION, OCCURRENCE_OPTION, OLD_ARCHIVE_OPTION, ONE_FILE_SYSTEM_OPTION, + ONE_TOP_LEVEL_OPTION, OVERWRITE_DIR_OPTION, OVERWRITE_OPTION, OWNER_OPTION, @@ -325,9 +336,12 @@ enum RMT_COMMAND_OPTION, RSH_COMMAND_OPTION, SAME_OWNER_OPTION, + SELINUX_CONTEXT_OPTION, SHOW_DEFAULTS_OPTION, SHOW_OMITTED_DIRS_OPTION, + SHOW_SNAPSHOT_FIELD_RANGES_OPTION, SHOW_TRANSFORMED_NAMES_OPTION, + SKIP_OLD_FILES_OPTION, SPARSE_VERSION_OPTION, STRIP_COMPONENTS_OPTION, SUFFIX_OPTION, @@ -340,13 +354,16 @@ enum VOLNO_FILE_OPTION, WARNING_OPTION, WILDCARDS_MATCH_SLASH_OPTION, - WILDCARDS_OPTION + WILDCARDS_OPTION, + XATTR_OPTION, + XATTR_EXCLUDE, + XATTR_INCLUDE }; const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION; const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; static char const doc[] = N_("\ -GNU `tar' saves many files together into a single tape or disk archive, \ +GNU 'tar' saves many files together into a single tape or disk archive, \ and can restore individual files from the archive.\n\ \n\ Examples:\n\ @@ -354,7 +371,7 @@ Examples:\n\ tar -tvf archive.tar # List all files in archive.tar verbosely.\n\ tar -xf archive.tar # Extract all files from archive.tar.\n") "\v" -N_("The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ +N_("The backup suffix is '~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ The version control may be set with --backup or VERSION_CONTROL, values are:\n\n\ none, off never make backups\n\ t, numbered make numbered backups\n\ @@ -452,7 +469,11 @@ static struct argp_option options[] = { {"remove-files", REMOVE_FILES_OPTION, 0, 0, N_("remove files after adding them to the archive"), GRID+1 }, {"keep-old-files", 'k', 0, 0, - N_("don't replace existing files when extracting"), GRID+1 }, + N_("don't replace existing files when extracting, " + "treat them as errors"), GRID+1 }, + {"skip-old-files", SKIP_OLD_FILES_OPTION, 0, 0, + N_("don't replace existing files when extracting, silently skip over them"), + GRID+1 }, {"keep-newer-files", KEEP_NEWER_FILES_OPTION, 0, 0, N_("don't replace existing files that are newer than their archive copies"), GRID+1 }, {"overwrite", OVERWRITE_OPTION, 0, 0, @@ -466,6 +487,12 @@ static struct argp_option options[] = { {"overwrite-dir", OVERWRITE_DIR_OPTION, 0, 0, N_("overwrite metadata of existing directories when extracting (default)"), GRID+1 }, + {"keep-directory-symlink", KEEP_DIRECTORY_SYMLINK_OPTION, 0, 0, + N_("preserve existing symlinks to directories when extracting"), + GRID+1 }, + {"one-top-level", ONE_TOP_LEVEL_OPTION, N_("DIR"), OPTION_ARG_OPTIONAL, + N_("create a subdirectory to avoid having loose files extracted"), + GRID+1 }, #undef GRID #define GRID 40 @@ -514,7 +541,8 @@ static struct argp_option options[] = { {"no-same-permissions", NO_SAME_PERMISSIONS_OPTION, 0, 0, N_("apply the user's umask when extracting permissions from the archive (default for ordinary users)"), GRID+1 }, {"preserve-order", 's', 0, 0, - N_("sort names to extract to match archive"), GRID+1 }, + N_("member arguments are listed in the same order as the " + "files in the archive"), GRID+1 }, {"same-order", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, {"preserve", PRESERVE_OPTION, 0, 0, N_("same as both -p and -s"), GRID+1 }, @@ -525,6 +553,28 @@ static struct argp_option options[] = { N_("cancel the effect of --delay-directory-restore option"), GRID+1 }, #undef GRID +#define GRID 55 + {NULL, 0, NULL, 0, + N_("Handling of extended file attributes:"), GRID }, + + {"xattrs", XATTR_OPTION, 0, 0, + N_("Enable extended attributes support"), GRID+1 }, + {"no-xattrs", NO_XATTR_OPTION, 0, 0, + N_("Disable extended attributes support"), GRID+1 }, + {"xattrs-include", XATTR_INCLUDE, N_("MASK"), 0, + N_("specify the include pattern for xattr keys"), GRID+1 }, + {"xattrs-exclude", XATTR_EXCLUDE, N_("MASK"), 0, + N_("specify the exclude pattern for xattr keys"), GRID+1 }, + {"selinux", SELINUX_CONTEXT_OPTION, 0, 0, + N_("Enable the SELinux context support"), GRID+1 }, + {"no-selinux", NO_SELINUX_CONTEXT_OPTION, 0, 0, + N_("Disable the SELinux context support"), GRID+1 }, + {"acls", ACLS_OPTION, 0, 0, + N_("Enable the POSIX ACLs support"), GRID+1 }, + {"no-acls", NO_ACLS_OPTION, 0, 0, + N_("Disable the POSIX ACLs support"), GRID+1 }, +#undef GRID + #define GRID 60 {NULL, 0, NULL, 0, N_("Device selection and switching:"), GRID }, @@ -538,7 +588,7 @@ static struct argp_option options[] = { {"rsh-command", RSH_COMMAND_OPTION, N_("COMMAND"), 0, N_("use remote COMMAND instead of rsh"), GRID+1 }, #ifdef DEVICE_PREFIX - {"-[0-7][lmh]", 0, NULL, OPTION_DOC, /* It is OK, since `name' will never be + {"-[0-7][lmh]", 0, NULL, OPTION_DOC, /* It is OK, since 'name' will never be translated */ N_("specify drive and density"), GRID+1 }, #endif @@ -680,13 +730,13 @@ static struct argp_option options[] = { {"recursion", RECURSION_OPTION, 0, 0, N_("recurse into directories (default)"), GRID+1 }, {"absolute-names", 'P', 0, 0, - N_("don't strip leading `/'s from file names"), GRID+1 }, + N_("don't strip leading '/'s from file names"), GRID+1 }, {"dereference", 'h', 0, 0, N_("follow symlinks; archive and dump the files they point to"), GRID+1 }, {"hard-dereference", HARD_DEREFERENCE_OPTION, 0, 0, N_("follow hard links; archive and dump the files they refer to"), GRID+1 }, {"starting-file", 'K', N_("MEMBER-NAME"), 0, - N_("begin at member MEMBER-NAME in the archive"), GRID+1 }, + N_("begin at member MEMBER-NAME when reading the archive"), GRID+1 }, {"newer", 'N', N_("DATE-OR-FILE"), 0, N_("only store files newer than DATE-OR-FILE"), GRID+1 }, {"after-date", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, @@ -718,7 +768,7 @@ static struct argp_option options[] = { {"anchored", ANCHORED_OPTION, 0, 0, N_("patterns match file name start"), GRID+1 }, {"no-anchored", NO_ANCHORED_OPTION, 0, 0, - N_("patterns match after any `/' (default for exclusion)"), GRID+1 }, + N_("patterns match after any '/' (default for exclusion)"), GRID+1 }, {"no-ignore-case", NO_IGNORE_CASE_OPTION, 0, 0, N_("case sensitive matching (default)"), GRID+1 }, {"wildcards", WILDCARDS_OPTION, 0, 0, @@ -726,9 +776,9 @@ static struct argp_option options[] = { {"no-wildcards", NO_WILDCARDS_OPTION, 0, 0, N_("verbatim string matching"), GRID+1 }, {"no-wildcards-match-slash", NO_WILDCARDS_MATCH_SLASH_OPTION, 0, 0, - N_("wildcards do not match `/'"), GRID+1 }, + N_("wildcards do not match '/'"), GRID+1 }, {"wildcards-match-slash", WILDCARDS_MATCH_SLASH_OPTION, 0, 0, - N_("wildcards match `/' (default for exclusion)"), GRID+1 }, + N_("wildcards match '/' (default for exclusion)"), GRID+1 }, #undef GRID #define GRID 130 @@ -765,6 +815,8 @@ static struct argp_option options[] = { {"confirmation", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, {"show-defaults", SHOW_DEFAULTS_OPTION, 0, 0, N_("show tar defaults"), GRID+1 }, + {"show-snapshot-field-ranges", SHOW_SNAPSHOT_FIELD_RANGES_OPTION, 0, 0, + N_("show valid ranges for snapshot-file fields"), GRID+1 }, {"show-omitted-dirs", SHOW_OMITTED_DIRS_OPTION, 0, 0, N_("when listing or extracting, list each directory that does not match search criteria"), GRID+1 }, {"show-transformed-names", SHOW_TRANSFORMED_NAMES_OPTION, 0, 0, @@ -892,12 +944,12 @@ static char const * const backup_file_table[] = { }; static void -add_exclude_array (char const * const * fv, int options) +add_exclude_array (char const * const * fv, int opts) { int i; for (i = 0; fv[i]; i++) - add_exclude (excluded, fv[i], options); + add_exclude (excluded, fv[i], opts); } @@ -927,7 +979,7 @@ set_subcommand_option (enum subcommand subcommand) if (subcommand_option != UNKNOWN_SUBCOMMAND && subcommand_option != subcommand) USAGE_ERROR ((0, 0, - _("You may not specify more than one `-Acdtrux' or `--test-label' option"))); + _("You may not specify more than one '-Acdtrux', '--delete' or '--test-label' option"))); subcommand_option = subcommand; } @@ -942,7 +994,7 @@ set_use_compress_program_option (const char *string) use_compress_program_option = string; } -static RETSIGTYPE +static void sigstat (int signo) { compute_duration (); @@ -956,10 +1008,13 @@ static void stat_on_signal (int signo) { #ifdef HAVE_SIGACTION +# ifndef SA_RESTART +# define SA_RESTART 0 +# endif struct sigaction act; act.sa_handler = sigstat; sigemptyset (&act.sa_mask); - act.sa_flags = 0; + act.sa_flags = SA_RESTART; sigaction (signo, &act, NULL); #else signal (signo, sigstat); @@ -1054,7 +1109,7 @@ report_textual_dates (struct tar_args *args) { char const *treated_as = tartime (p->ts, true); if (strcmp (p->date, treated_as) != 0) - WARN ((0, 0, _("Option %s: Treating date `%s' as %s"), + WARN ((0, 0, _("Option %s: Treating date '%s' as %s"), p->option, p->date, treated_as)); } free (p->date); @@ -1063,194 +1118,26 @@ report_textual_dates (struct tar_args *args) } } - - -/* Either NL or NUL, as decided by the --null option. */ -static char filename_terminator; - -enum read_file_list_state /* Result of reading file name from the list file */ - { - file_list_success, /* OK, name read successfully */ - file_list_end, /* End of list file */ - file_list_zero, /* Zero separator encountered where it should not */ - file_list_skip /* Empty (zero-length) entry encountered, skip it */ - }; - -/* Read from FP a sequence of characters up to TERM and put them - into STK. - */ -static enum read_file_list_state -read_name_from_file (FILE *fp, struct obstack *stk, int term) -{ - int c; - size_t counter = 0; - - for (c = getc (fp); c != EOF && c != term; c = getc (fp)) - { - if (c == 0) - { - /* We have read a zero separator. The file possibly is - zero-separated */ - return file_list_zero; - } - obstack_1grow (stk, c); - counter++; - } - - if (counter == 0 && c != EOF) - return file_list_skip; - - obstack_1grow (stk, 0); - - return (counter == 0 && c == EOF) ? file_list_end : file_list_success; -} - static bool files_from_option; /* When set, tar will not refuse to create empty archives */ -static struct obstack argv_stk; /* Storage for additional command line options - read using -T option */ - -/* Prevent recursive inclusion of the same file */ -struct file_id_list -{ - struct file_id_list *next; - ino_t ino; - dev_t dev; -}; - -static struct file_id_list *file_id_list; - -static void -add_file_id (const char *filename) -{ - struct file_id_list *p; - struct stat st; - - if (stat (filename, &st)) - stat_fatal (filename); - for (p = file_id_list; p; p = p->next) - if (p->ino == st.st_ino && p->dev == st.st_dev) - { - FATAL_ERROR ((0, 0, _("%s: file list already read"), - quotearg_colon (filename))); - } - p = xmalloc (sizeof *p); - p->next = file_id_list; - p->ino = st.st_ino; - p->dev = st.st_dev; - file_id_list = p; -} /* Default density numbers for [0-9][lmh] device specifications */ -#ifndef LOW_DENSITY_NUM -# define LOW_DENSITY_NUM 0 -#endif +#if defined DEVICE_PREFIX && !defined DENSITY_LETTER +# ifndef LOW_DENSITY_NUM +# define LOW_DENSITY_NUM 0 +# endif -#ifndef MID_DENSITY_NUM -# define MID_DENSITY_NUM 8 -#endif +# ifndef MID_DENSITY_NUM +# define MID_DENSITY_NUM 8 +# endif -#ifndef HIGH_DENSITY_NUM -# define HIGH_DENSITY_NUM 16 +# ifndef HIGH_DENSITY_NUM +# define HIGH_DENSITY_NUM 16 +# endif #endif -static void -update_argv (const char *filename, struct argp_state *state) -{ - FILE *fp; - size_t count = 0, i; - char *start, *p; - char **new_argv; - size_t new_argc; - bool is_stdin = false; - enum read_file_list_state read_state; - int term = filename_terminator; - - if (!strcmp (filename, "-")) - { - is_stdin = true; - request_stdin ("-T"); - fp = stdin; - } - else - { - add_file_id (filename); - if ((fp = fopen (filename, "r")) == NULL) - open_fatal (filename); - } - - while ((read_state = read_name_from_file (fp, &argv_stk, term)) - != file_list_end) - { - switch (read_state) - { - case file_list_success: - count++; - break; - - case file_list_end: /* won't happen, just to pacify gcc */ - break; - - case file_list_zero: - { - size_t size; - - WARNOPT (WARN_FILENAME_WITH_NULS, - (0, 0, N_("%s: file name read contains nul character"), - quotearg_colon (filename))); - - /* Prepare new stack contents */ - size = obstack_object_size (&argv_stk); - p = obstack_finish (&argv_stk); - for (; size > 0; size--, p++) - if (*p) - obstack_1grow (&argv_stk, *p); - else - obstack_1grow (&argv_stk, '\n'); - obstack_1grow (&argv_stk, 0); - count = 1; - /* Read rest of files using new filename terminator */ - term = 0; - break; - } - - case file_list_skip: - break; - } - } - - if (!is_stdin) - fclose (fp); - - if (count == 0) - return; - - start = obstack_finish (&argv_stk); - - if (term == 0) - for (p = start; *p; p += strlen (p) + 1) - if (p[0] == '-') - count++; - - new_argc = state->argc + count; - new_argv = xmalloc (sizeof (state->argv[0]) * (new_argc + 1)); - memcpy (new_argv, state->argv, sizeof (state->argv[0]) * (state->argc + 1)); - state->argv = new_argv; - memmove (&state->argv[state->next + count], &state->argv[state->next], - (state->argc - state->next + 1) * sizeof (state->argv[0])); - - state->argc = new_argc; - - for (i = state->next, p = start; *p; p += strlen (p) + 1, i++) - { - if (term == 0 && p[0] == '-') - state->argv[i++] = "--add-file"; - state->argv[i] = p; - } -} - static char * tar_help_filter (int key, const char *text, void *input) @@ -1284,6 +1171,9 @@ tar_help_filter (int key, const char *text, void *input) s = xasprintf (_("filter the archive through %s"), LZMA_PROGRAM); break; + case LZOP_OPTION: + s = xasprintf (_("filter the archive through %s"), LZOP_PROGRAM); + case 'J': s = xasprintf (_("filter the archive through %s"), XZ_PROGRAM); break; @@ -1336,8 +1226,8 @@ expand_pax_option (struct tar_args *targs, const char *arg) tmp[len-2] = 0; if (get_date_or_file (targs, "--pax-option", tmp, &ts) == 0) { - char buf[UINTMAX_STRSIZE_BOUND], *s; - s = umaxtostr (ts.tv_sec, buf); + char buf[TIMESPEC_STRSIZE_BOUND]; + char const *s = code_timespec (ts, buf); obstack_grow (&stk, s, strlen (s)); } else @@ -1367,7 +1257,6 @@ expand_pax_option (struct tar_args *targs, const char *arg) static uintmax_t parse_owner_group (char *arg, uintmax_t field_max, char const **name_option) { - strtol_error err; uintmax_t u = UINTMAX_MAX; char *end; char const *name = 0; @@ -1418,6 +1307,9 @@ parse_owner_group (char *arg, uintmax_t field_max, char const **name_option) #define TAR_SIZE_SUFFIXES "bBcGgkKMmPTtw" +/* Either NL or NUL, as decided by the --null option. */ +static char filename_terminator; + static error_t parse_opt (int key, char *arg, struct argp_state *state) { @@ -1553,6 +1445,11 @@ parse_opt (int key, char *arg, struct argp_state *state) one_file_system_option = true; break; + case ONE_TOP_LEVEL_OPTION: + one_top_level_option = true; + one_top_level_dir = arg; + break; + case 'l': check_links_option = 1; break; @@ -1671,6 +1568,10 @@ parse_opt (int key, char *arg, struct argp_state *state) sparse_option = true; break; + case SKIP_OLD_FILES_OPTION: + old_files_option = SKIP_OLD_FILES; + break; + case SPARSE_VERSION_OPTION: sparse_option = true; { @@ -1697,7 +1598,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case 'T': - update_argv (arg, state); + name_add_file (arg, filename_terminator); /* Indicate we've been given -T option. This is for backward compatibility only, so that `tar cfT archive /dev/null will succeed */ @@ -1883,6 +1784,10 @@ parse_opt (int key, char *arg, struct argp_state *state) ignore_failed_read_option = true; break; + case KEEP_DIRECTORY_SYMLINK_OPTION: + keep_directory_symlink_option = true; + break; + case KEEP_NEWER_FILES_OPTION: old_files_option = KEEP_NEWER_FILES; break; @@ -1966,6 +1871,10 @@ parse_opt (int key, char *arg, struct argp_state *state) } break; + case OLD_ARCHIVE_OPTION: + set_archive_format ("v7"); + break; + case OVERWRITE_DIR_OPTION: old_files_option = DEFAULT_OLD_FILES; break; @@ -2064,6 +1973,11 @@ parse_opt (int key, char *arg, struct argp_state *state) exit (0); } + case SHOW_SNAPSHOT_FIELD_RANGES_OPTION: + show_snapshot_field_ranges (); + close_stdout (); + exit (0); + case STRIP_COMPONENTS_OPTION: { uintmax_t u; @@ -2133,6 +2047,38 @@ parse_opt (int key, char *arg, struct argp_state *state) same_permissions_option = -1; break; + case ACLS_OPTION: + set_archive_format ("posix"); + acls_option = 1; + break; + + case NO_ACLS_OPTION: + acls_option = -1; + break; + + case SELINUX_CONTEXT_OPTION: + set_archive_format ("posix"); + selinux_context_option = 1; + break; + + case NO_SELINUX_CONTEXT_OPTION: + selinux_context_option = -1; + break; + + case XATTR_OPTION: + set_archive_format ("posix"); + xattrs_option = 1; + break; + + case NO_XATTR_OPTION: + xattrs_option = -1; + break; + + case XATTR_INCLUDE: + case XATTR_EXCLUDE: + xattrs_mask_add (arg, (key == XATTR_INCLUDE)); + break; + case RECURSION_OPTION: recursion_option = FNM_LEADING_DIR; break; @@ -2196,7 +2142,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; default: - argp_error (state, _("Unknown density: `%c'"), arg[0]); + argp_error (state, _("Unknown density: '%c'"), arg[0]); } sprintf (cursor, "%d", device); @@ -2213,7 +2159,7 @@ parse_opt (int key, char *arg, struct argp_state *state) #else /* not DEVICE_PREFIX */ argp_error (state, - _("Options `-[0-7][lmh]' not supported by *this* tar")); + _("Options '-[0-7][lmh]' not supported by *this* tar")); #endif /* not DEVICE_PREFIX */ @@ -2262,12 +2208,37 @@ static const char *tar_authors[] = { "Jay Fenlason", NULL }; + +/* Subcommand classes */ +#define SUBCL_READ 0x01 /* subcommand reads from the archive */ +#define SUBCL_WRITE 0x02 /* subcommand writes to the archive */ +#define SUBCL_UPDATE 0x04 /* subcommand updates existing archive */ +#define SUBCL_TEST 0x08 /* subcommand tests archive header or meta-info */ +#define SUBCL_OCCUR 0x10 /* subcommand allows the use of the occurrence + option */ + +static int subcommand_class[] = { + /* UNKNOWN_SUBCOMMAND */ 0, + /* APPEND_SUBCOMMAND */ SUBCL_WRITE|SUBCL_UPDATE, + /* CAT_SUBCOMMAND */ SUBCL_WRITE, + /* CREATE_SUBCOMMAND */ SUBCL_WRITE, + /* DELETE_SUBCOMMAND */ SUBCL_WRITE|SUBCL_UPDATE|SUBCL_OCCUR, + /* DIFF_SUBCOMMAND */ SUBCL_READ|SUBCL_OCCUR, + /* EXTRACT_SUBCOMMAND */ SUBCL_READ|SUBCL_OCCUR, + /* LIST_SUBCOMMAND */ SUBCL_READ|SUBCL_OCCUR, + /* UPDATE_SUBCOMMAND */ SUBCL_WRITE|SUBCL_UPDATE, + /* TEST_LABEL_SUBCOMMAND */ SUBCL_TEST +}; + +/* Return t if the subcommand_option is in class(es) f */ +#define IS_SUBCOMMAND_CLASS(f) (subcommand_class[subcommand_option] & (f)) + +static struct tar_args args; static void decode_options (int argc, char **argv) { int idx; - struct tar_args args; argp_version_setup ("tar", tar_authors); @@ -2344,7 +2315,7 @@ decode_options (int argc, char **argv) if (in < argv + argc) *out++ = *in++; else - USAGE_ERROR ((0, 0, _("Old option `%c' requires an argument."), + USAGE_ERROR ((0, 0, _("Old option '%c' requires an argument."), *letter)); } } @@ -2368,7 +2339,6 @@ decode_options (int argc, char **argv) if (argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &idx, &args)) exit (TAREXIT_FAILURE); - /* Special handling for 'o' option: GNU tar used to say "output old format". @@ -2426,14 +2396,15 @@ decode_options (int argc, char **argv) if (!args.input_files) USAGE_ERROR ((0, 0, _("--occurrence is meaningless without a file list"))); - if (subcommand_option != DELETE_SUBCOMMAND - && subcommand_option != DIFF_SUBCOMMAND - && subcommand_option != EXTRACT_SUBCOMMAND - && subcommand_option != LIST_SUBCOMMAND) - USAGE_ERROR ((0, 0, - _("--occurrence cannot be used in the requested operation mode"))); + if (!IS_SUBCOMMAND_CLASS (SUBCL_OCCUR)) + USAGE_ERROR ((0, 0, + _("--occurrence cannot be used with %s"), + subcommand_string (subcommand_option))); } + if (one_top_level_option && absolute_names_option) + USAGE_ERROR ((0, 0, _("--one-top-level cannot be used with --absolute-names"))); + if (archive_names == 0) { /* If no archive file name given, try TAPE from the environment, or @@ -2445,11 +2416,11 @@ decode_options (int argc, char **argv) archive_name_array[0] = DEFAULT_ARCHIVE; } - /* Allow multiple archives only with `-M'. */ + /* Allow multiple archives only with '-M'. */ if (archive_names > 1 && !multi_volume_option) USAGE_ERROR ((0, 0, - _("Multiple archive files require `-M' option"))); + _("Multiple archive files require '-M' option"))); if (listed_incremental_option && NEWER_OPTION_INITIALIZED (newer_mtime_option)) @@ -2490,15 +2461,16 @@ decode_options (int argc, char **argv) USAGE_ERROR ((0, 0, _("Cannot verify multi-volume archives"))); if (use_compress_program_option) USAGE_ERROR ((0, 0, _("Cannot verify compressed archives"))); + if (!IS_SUBCOMMAND_CLASS (SUBCL_WRITE)) + USAGE_ERROR ((0, 0, _("--verify cannot be used with %s"), + subcommand_string (subcommand_option))); } if (use_compress_program_option) { if (multi_volume_option) USAGE_ERROR ((0, 0, _("Cannot use multi-volume compressed archives"))); - if (subcommand_option == UPDATE_SUBCOMMAND - || subcommand_option == APPEND_SUBCOMMAND - || subcommand_option == DELETE_SUBCOMMAND) + if (IS_SUBCOMMAND_CLASS (SUBCL_UPDATE)) USAGE_ERROR ((0, 0, _("Cannot update compressed archives"))); if (subcommand_option == CAT_SUBCOMMAND) USAGE_ERROR ((0, 0, _("Cannot concatenate compressed archives"))); @@ -2510,11 +2482,33 @@ decode_options (int argc, char **argv) --gray */ if (args.pax_option && archive_format != POSIX_FORMAT - && (subcommand_option != EXTRACT_SUBCOMMAND - || subcommand_option != DIFF_SUBCOMMAND - || subcommand_option != LIST_SUBCOMMAND)) + && !IS_SUBCOMMAND_CLASS (SUBCL_READ)) USAGE_ERROR ((0, 0, _("--pax-option can be used only on POSIX archives"))); + /* star creates non-POSIX typed archives with xattr support, so allow the + extra headers when reading */ + if ((acls_option > 0) + && archive_format != POSIX_FORMAT + && !IS_SUBCOMMAND_CLASS (SUBCL_READ)) + USAGE_ERROR ((0, 0, _("--acls can be used only on POSIX archives"))); + + if ((selinux_context_option > 0) + && archive_format != POSIX_FORMAT + && !IS_SUBCOMMAND_CLASS (SUBCL_READ)) + USAGE_ERROR ((0, 0, _("--selinux can be used only on POSIX archives"))); + + if ((xattrs_option > 0) + && archive_format != POSIX_FORMAT + && !IS_SUBCOMMAND_CLASS (SUBCL_READ)) + USAGE_ERROR ((0, 0, _("--xattrs can be used only on POSIX archives"))); + + if ((starting_file_option || same_order_option) + && !IS_SUBCOMMAND_CLASS (SUBCL_READ)) + USAGE_ERROR ((0, 0, + _("--%s option cannot be used with %s"), + starting_file_option ? "starting-file" : "same-order", + subcommand_string (subcommand_option))); + /* If ready to unlink hierarchies, so we are for simpler files. */ if (recursive_unlink_option) old_files_option = UNLINK_FIRST_OLD_FILES; @@ -2549,7 +2543,7 @@ decode_options (int argc, char **argv) USAGE_ERROR ((0, 0, _("--preserve-order is not compatible with " "--listed-incremental"))); - /* Forbid using -c with no input files whatsoever. Check that `-f -', + /* Forbid using -c with no input files whatsoever. Check that '-f -', explicit or implied, is used correctly. */ switch (subcommand_option) @@ -2583,7 +2577,7 @@ decode_options (int argc, char **argv) archive_name_cursor++) if (!strcmp (*archive_name_cursor, "-")) USAGE_ERROR ((0, 0, - _("Options `-Aru' are incompatible with `-f -'"))); + _("Options '-Aru' are incompatible with '-f -'"))); default: break; @@ -2594,7 +2588,7 @@ decode_options (int argc, char **argv) { stdlis = fopen (index_file_name, "w"); if (! stdlis) - open_error (index_file_name); + open_fatal (index_file_name); } else stdlis = to_stdout_option ? stderr : stdout; @@ -2620,6 +2614,14 @@ decode_options (int argc, char **argv) report_textual_dates (&args); } +void +more_options (int argc, char **argv) +{ + int idx; + if (argp_parse (&argp, argc, argv, ARGP_IN_ORDER, + &idx, &args)) + exit (TAREXIT_FAILURE); +} /* Tar proper. */ @@ -2636,6 +2638,8 @@ main (int argc, char **argv) exit_failure = TAREXIT_FAILURE; exit_status = TAREXIT_SUCCESS; + error_hook = checkpoint_flush_actions; + filename_terminator = '\n'; set_quoting_style (0, DEFAULT_QUOTING_STYLE); @@ -2649,8 +2653,6 @@ main (int argc, char **argv) xmalloc (sizeof (const char *) * allocated_archive_names); archive_names = 0; - obstack_init (&argv_stk); - /* System V fork+wait does not work if SIGCHLD is ignored. */ signal (SIGCHLD, SIG_DFL); @@ -2672,7 +2674,7 @@ main (int argc, char **argv) { case UNKNOWN_SUBCOMMAND: USAGE_ERROR ((0, 0, - _("You must specify one of the `-Acdtrux' or `--test-label' options"))); + _("You must specify one of the '-Acdtrux', '--delete' or '--test-label' options"))); case CAT_SUBCOMMAND: case UPDATE_SUBCOMMAND: @@ -2711,6 +2713,8 @@ main (int argc, char **argv) test_archive_label (); } + checkpoint_finish (); + if (totals_option) print_total_stats (); @@ -2723,6 +2727,7 @@ main (int argc, char **argv) /* Dispose of allocated memory, and return. */ free (archive_name_array); + xattrs_clear_setup (); name_term (); if (exit_status == TAREXIT_FAILURE) @@ -2767,11 +2772,15 @@ void tar_stat_destroy (struct tar_stat_info *st) { tar_stat_close (st); + xheader_xattr_free (st->xattr_map, st->xattr_map_size); free (st->orig_file_name); free (st->file_name); free (st->link_name); free (st->uname); free (st->gname); + free (st->cntx_name); + free (st->acls_a_ptr); + free (st->acls_d_ptr); free (st->sparse_map); free (st->dumpdir); xheader_destroy (&st->xhdr);