X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Ftar.c;h=6c327f707def2bf3f7109e80bc676f2b10a2f68a;hb=2c06a80918019471876956eef4ef22f05c9e0571;hp=e8813de63f6e6595e76903eca283f819e5a2fef5;hpb=085cace1805308589c6211429068f68047be0b0e;p=chaz%2Ftar diff --git a/src/tar.c b/src/tar.c index e8813de..6c327f7 100644 --- a/src/tar.c +++ b/src/tar.c @@ -1,8 +1,7 @@ /* A tar (tape archiver) program. - Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, - 2001, 2003, 2004, 2005, 2006, 2007, 2012 - Free Software Foundation, Inc. + Copyright 1988, 1992-1997, 1999-2001, 2003-2007, 2012-2013 Free + Software Foundation, Inc. Written by John Gilmore, starting 1985-08-25. @@ -17,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 @@ -68,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. */ @@ -75,7 +79,7 @@ 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) @@ -282,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, @@ -333,6 +338,7 @@ enum 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, @@ -480,6 +486,9 @@ 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 }, #undef GRID #define GRID 40 @@ -801,6 +810,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, @@ -963,7 +974,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; } @@ -1102,84 +1113,9 @@ 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 */ @@ -1197,101 +1133,6 @@ add_file_id (const char *filename) # 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) @@ -1377,8 +1218,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 @@ -1458,6 +1299,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) { @@ -1741,7 +1585,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 */ @@ -1927,6 +1771,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; @@ -2013,7 +1861,7 @@ parse_opt (int key, char *arg, struct argp_state *state) case OLD_ARCHIVE_OPTION: set_archive_format ("v7"); break; - + case OVERWRITE_DIR_OPTION: old_files_option = DEFAULT_OLD_FILES; break; @@ -2112,6 +1960,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; @@ -2342,12 +2195,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); @@ -2448,7 +2326,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". @@ -2506,12 +2383,10 @@ 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 (archive_names == 0) @@ -2570,15 +2445,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"))); @@ -2590,24 +2466,24 @@ decode_options (int argc, char **argv) --gray */ if (args.pax_option && archive_format != POSIX_FORMAT - && !READ_LIKE_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 whenn reading */ + extra headers when reading */ if ((acls_option > 0) && archive_format != POSIX_FORMAT - && !READ_LIKE_SUBCOMMAND) + && !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 - && !READ_LIKE_SUBCOMMAND) + && !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 - && !READ_LIKE_SUBCOMMAND) + && !IS_SUBCOMMAND_CLASS (SUBCL_READ)) USAGE_ERROR ((0, 0, _("--xattrs can be used only on POSIX archives"))); /* If ready to unlink hierarchies, so we are for simpler files. */ @@ -2715,6 +2591,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. */ @@ -2744,8 +2628,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); @@ -2767,7 +2649,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: