X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Ftar.c;h=e3f82f123e791803da0af9c6e8807e07c3525893;hb=d36f5a3cc3280d6c4a58367bf51b527d5c14ac04;hp=d80a10f03613e46b8c51430b6183ff8ff800cd82;hpb=14efeb9f956e38d7beaf3fbedb04d3f3bb9ece3a;p=chaz%2Ftar diff --git a/src/tar.c b/src/tar.c index d80a10f..e3f82f1 100644 --- a/src/tar.c +++ b/src/tar.c @@ -1,7 +1,8 @@ /* 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. + 2001, 2003, 2004, 2005, 2006, 2007, 2012 + Free Software Foundation, Inc. Written by John Gilmore, starting 1985-08-25. @@ -43,7 +44,7 @@ #include #include #include -#include +#include #include #include #include @@ -78,7 +79,7 @@ static 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 +248,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 +256,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, @@ -288,6 +290,7 @@ enum MODE_OPTION, MTIME_OPTION, NEWER_MTIME_OPTION, + NO_ACLS_OPTION, NO_ANCHORED_OPTION, NO_AUTO_COMPRESS_OPTION, NO_CHECK_DEVICE_OPTION, @@ -304,6 +307,7 @@ enum NO_UNQUOTE_OPTION, NO_WILDCARDS_MATCH_SLASH_OPTION, NO_WILDCARDS_OPTION, + NO_XATTR_OPTION, NULL_OPTION, NUMERIC_OWNER_OPTION, OCCURRENCE_OPTION, @@ -328,6 +332,7 @@ enum SHOW_DEFAULTS_OPTION, SHOW_OMITTED_DIRS_OPTION, SHOW_TRANSFORMED_NAMES_OPTION, + SKIP_OLD_FILES_OPTION, SPARSE_VERSION_OPTION, STRIP_COMPONENTS_OPTION, SUFFIX_OPTION, @@ -340,13 +345,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 +362,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 +460,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, @@ -525,6 +537,24 @@ 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 }, + {"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 +568,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,7 +710,7 @@ 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, @@ -718,7 +748,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 +756,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 @@ -892,12 +922,12 @@ static char const * const backup_file_table[] = { }; static void -add_exclude_array (char const * const * fv) +add_exclude_array (char const * const * fv, int opts) { int i; for (i = 0; fv[i]; i++) - add_exclude (excluded, fv[i], 0); + add_exclude (excluded, fv[i], opts); } @@ -927,7 +957,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' or '--test-label' option"))); subcommand_option = subcommand; } @@ -956,10 +986,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); @@ -1023,7 +1056,7 @@ get_date_or_file (struct tar_args *args, const char *option, } else { - if (! get_date (ts, str, NULL)) + if (! parse_datetime (ts, str, NULL)) { WARN ((0, 0, _("Substituting %s for unknown date format %s"), tartime (*ts, false), quote (str))); @@ -1054,7 +1087,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); @@ -1144,16 +1177,18 @@ add_file_id (const char *filename) /* 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 @@ -1364,6 +1399,57 @@ 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) +{ + uintmax_t u = UINTMAX_MAX; + char *end; + char const *name = 0; + char const *invalid_num = 0; + char *colon = strchr (arg, ':'); + + if (colon) + { + char const *num = colon + 1; + *colon = '\0'; + if (*arg) + name = arg; + if (num && (! (xstrtoumax (num, &end, 10, &u, "") == LONGINT_OK + && u <= field_max))) + invalid_num = num; + } + else + { + uintmax_t u1; + switch ('0' <= *arg && *arg <= '9' + ? xstrtoumax (arg, &end, 10, &u1, "") + : LONGINT_INVALID) + { + default: + name = arg; + break; + + case LONGINT_OK: + if (u1 <= field_max) + { + u = u1; + break; + } + /* Fall through. */ + case LONGINT_OVERFLOW: + invalid_num = arg; + break; + } + } + + if (invalid_num) + FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (invalid_num), + _("Invalid owner or group ID"))); + if (name) + *name_option = name; + return u; +} + #define TAR_SIZE_SUFFIXES "bBcGgkKMmPTtw" static error_t @@ -1619,6 +1705,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; { @@ -1769,7 +1859,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case EXCLUDE_BACKUPS_OPTION: - add_exclude_array (backup_file_table); + add_exclude_array (backup_file_table, EXCLUDE_WILDCARDS); break; case EXCLUDE_OPTION: @@ -1804,7 +1894,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case EXCLUDE_VCS_OPTION: - add_exclude_array (vcs_file_table); + add_exclude_array (vcs_file_table, 0); break; case FORCE_LOCAL_OPTION: @@ -1836,17 +1926,18 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case GROUP_OPTION: - if (! (strlen (arg) < GNAME_FIELD_SIZE - && gname_to_gid (arg, &group_option))) - { - uintmax_t g; - if (xstrtoumax (arg, 0, 10, &g, "") == LONGINT_OK - && g == (gid_t) g) - group_option = g; - else - FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (arg), - _("Invalid group"))); - } + { + uintmax_t u = parse_owner_group (arg, TYPE_MAXIMUM (gid_t), + &group_name_option); + if (u == UINTMAX_MAX) + { + group_option = -1; + if (group_name_option) + gname_to_gid (group_name_option, &group_option); + } + else + group_option = u; + } break; case MODE_OPTION: @@ -1913,6 +2004,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; @@ -1922,17 +2017,18 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case OWNER_OPTION: - if (! (strlen (arg) < UNAME_FIELD_SIZE - && uname_to_uid (arg, &owner_option))) - { - uintmax_t u; - if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK - && u == (uid_t) u) - owner_option = u; - else - FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (arg), - _("Invalid owner"))); - } + { + uintmax_t u = parse_owner_group (arg, TYPE_MAXIMUM (uid_t), + &owner_name_option); + if (u == UINTMAX_MAX) + { + owner_option = -1; + if (owner_name_option) + uname_to_uid (owner_name_option, &owner_option); + } + else + owner_option = u; + } break; case QUOTE_CHARS_OPTION: @@ -2079,6 +2175,29 @@ 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 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; @@ -2142,7 +2261,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); @@ -2159,7 +2278,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 */ @@ -2241,8 +2360,8 @@ decode_options (int argc, char **argv) tar_sparse_major = 1; tar_sparse_minor = 0; - owner_option = -1; - group_option = -1; + owner_option = -1; owner_name_option = NULL; + group_option = -1; group_name_option = NULL; check_device_option = true; @@ -2290,7 +2409,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)); } } @@ -2391,11 +2510,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)) @@ -2456,11 +2575,21 @@ 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)) + && !READ_LIKE_SUBCOMMAND) 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 whenn reading */ + if ((acls_option > 0) + && archive_format != POSIX_FORMAT + && !READ_LIKE_SUBCOMMAND) + USAGE_ERROR ((0, 0, _("--acls can be used only on POSIX archives"))); + + if ((xattrs_option > 0) + && archive_format != POSIX_FORMAT + && !READ_LIKE_SUBCOMMAND) + USAGE_ERROR ((0, 0, _("--xattrs can be used only on POSIX archives"))); + /* If ready to unlink hierarchies, so we are for simpler files. */ if (recursive_unlink_option) old_files_option = UNLINK_FIRST_OLD_FILES; @@ -2495,7 +2624,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) @@ -2529,7 +2658,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; @@ -2540,7 +2669,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; @@ -2618,7 +2747,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' or '--test-label' options"))); case CAT_SUBCOMMAND: case UPDATE_SUBCOMMAND: @@ -2669,6 +2798,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) @@ -2713,11 +2843,14 @@ 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->acls_a_ptr); + free (st->acls_d_ptr); free (st->sparse_map); free (st->dumpdir); xheader_destroy (&st->xhdr);