X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Ftar.c;h=8d23a4faa656f270dee2a3b70838003a035e81ad;hb=1bcbbcf1ff2c537ffa970dbf82e3843d4ad110e5;hp=41a53ec5a4f62b53458c081b7d326dbd764d57fc;hpb=620a136e74f211c2fb98b45fe44261d5d775f6a9;p=chaz%2Ftar diff --git a/src/tar.c b/src/tar.c index 41a53ec..8d23a4f 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 Free Software Foundation, Inc. + 2001, 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc. Written by John Gilmore, starting 1985-08-25. @@ -50,6 +50,7 @@ #include #include #include +#include /* Local declarations. */ @@ -249,8 +250,11 @@ enum ANCHORED_OPTION = CHAR_MAX + 1, ATIME_PRESERVE_OPTION, BACKUP_OPTION, + CHECK_DEVICE_OPTION, CHECKPOINT_OPTION, + CHECKPOINT_ACTION_OPTION, DELAY_DIRECTORY_RESTORE_OPTION, + HARD_DEREFERENCE_OPTION, DELETE_OPTION, EXCLUDE_CACHES_OPTION, EXCLUDE_CACHES_UNDER_OPTION, @@ -268,14 +272,19 @@ enum IGNORE_FAILED_READ_OPTION, INDEX_FILE_OPTION, KEEP_NEWER_FILES_OPTION, + LEVEL_OPTION, LZMA_OPTION, + LZOP_OPTION, MODE_OPTION, MTIME_OPTION, NEWER_MTIME_OPTION, NO_ANCHORED_OPTION, + NO_AUTO_COMPRESS_OPTION, + NO_CHECK_DEVICE_OPTION, NO_DELAY_DIRECTORY_RESTORE_OPTION, NO_IGNORE_CASE_OPTION, NO_IGNORE_COMMAND_ERROR_OPTION, + NO_NULL_OPTION, NO_OVERWRITE_DIR_OPTION, NO_QUOTE_CHARS_OPTION, NO_RECURSION_OPTION, @@ -317,10 +326,10 @@ enum TRANSFORM_OPTION, UNQUOTE_OPTION, USAGE_OPTION, - USE_COMPRESS_PROGRAM_OPTION, UTC_OPTION, VERSION_OPTION, VOLNO_FILE_OPTION, + WARNING_OPTION, WILDCARDS_MATCH_SLASH_OPTION, WILDCARDS_OPTION }; @@ -346,7 +355,7 @@ The version control may be set with --backup or VERSION_CONTROL, values are:\n\n /* NOTE: - Available option letters are DEIJQY and eqy. Consider the following + Available option letters are DEQY and eqy. Consider the following assignments: [For Solaris tar compatibility =/= Is it important at all?] @@ -354,7 +363,6 @@ The version control may be set with --backup or VERSION_CONTROL, values are:\n\n E use extended headers (--format=posix) [q alias for --occurrence=1 =/= this would better be used for quiet?] - [I same as T =/= will harm star compatibility] y per-file gzip compression Y per-block gzip compression */ @@ -399,6 +407,8 @@ static struct argp_option options[] = { N_("handle old GNU-format incremental backup"), GRID+1 }, {"listed-incremental", 'g', N_("FILE"), 0, N_("handle new GNU-format incremental backup"), GRID+1 }, + {"level", LEVEL_OPTION, N_("NUMBER"), 0, + N_("dump level for created listed-incremental archive"), GRID+1 }, {"ignore-failed-read", IGNORE_FAILED_READ_OPTION, 0, 0, N_("do not exit with nonzero on unreadable files"), GRID+1 }, {"occurrence", OCCURRENCE_OPTION, N_("NUMBER"), OPTION_ARG_OPTIONAL, @@ -409,6 +419,12 @@ static struct argp_option options[] = { " NUMBER defaults to 1"), GRID+1 }, {"seek", 'n', NULL, 0, N_("archive is seekable"), GRID+1 }, + {"no-check-device", NO_CHECK_DEVICE_OPTION, NULL, 0, + N_("do not check device numbers when creating incremental archives"), + GRID+1 }, + {"check-device", CHECK_DEVICE_OPTION, NULL, 0, + N_("check device numbers when creating incremental archives (default)"), + GRID+1 }, #undef GRID #define GRID 30 @@ -470,9 +486,9 @@ static struct argp_option options[] = { {"touch", 'm', 0, 0, N_("don't extract file modified time"), GRID+1 }, {"same-owner", SAME_OWNER_OPTION, 0, 0, - N_("try extracting files with the same ownership"), GRID+1 }, + N_("try extracting files with the same ownership as exists in the archive (default for superuser)"), GRID+1 }, {"no-same-owner", NO_SAME_OWNER_OPTION, 0, 0, - N_("extract files as yourself"), GRID+1 }, + N_("extract files as yourself (default for ordinary users)"), GRID+1 }, {"numeric-owner", NUMERIC_OWNER_OPTION, 0, 0, N_("always use numbers for user/group names"), GRID+1 }, {"preserve-permissions", 'p', 0, 0, @@ -582,6 +598,9 @@ static struct argp_option options[] = { N_("Compression options:"), GRID }, {"auto-compress", 'a', 0, 0, N_("use archive suffix to determine the compression program"), GRID+1 }, + {"no-auto-compress", NO_AUTO_COMPRESS_OPTION, 0, 0, + N_("do not use archive suffix to determine the compression program"), + GRID+1 }, {"bzip2", 'j', 0, 0, N_("filter the archive through bzip2"), GRID+1 }, {"gzip", 'z', 0, 0, @@ -593,7 +612,11 @@ static struct argp_option options[] = { {"uncompress", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, {"lzma", LZMA_OPTION, 0, 0, N_("filter the archive through lzma"), GRID+1 }, - {"use-compress-program", USE_COMPRESS_PROGRAM_OPTION, N_("PROG"), 0, + {"lzop", LZOP_OPTION, 0, 0, + N_("filter the archive through lzop"), GRID+8 }, + {"xz", 'J', 0, 0, + N_("filter the archive through xz"), GRID+8 }, + {"use-compress-program", 'I', N_("PROG"), 0, N_("filter through PROG (must accept -d)"), GRID+1 }, #undef GRID @@ -609,6 +632,8 @@ static struct argp_option options[] = { N_("get names to extract or create from FILE"), GRID+1 }, {"null", NULL_OPTION, 0, 0, N_("-T reads null-terminated names, disable -C"), GRID+1 }, + {"no-null", NO_NULL_OPTION, 0, 0, + N_("disable the effect of the previous --null option"), GRID+1 }, {"unquote", UNQUOTE_OPTION, 0, 0, N_("unquote filenames read with -T (default)"), GRID+1 }, {"no-unquote", NO_UNQUOTE_OPTION, 0, 0, @@ -644,6 +669,8 @@ static struct argp_option options[] = { 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 }, {"newer", 'N', N_("DATE-OR-FILE"), 0, @@ -665,6 +692,7 @@ static struct argp_option options[] = { GRID+1 }, {"transform", TRANSFORM_OPTION, N_("EXPRESSION"), 0, N_("use sed replace EXPRESSION to transform file names"), GRID+1 }, + {"xform", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, #undef GRID #define GRID 120 @@ -695,9 +723,14 @@ static struct argp_option options[] = { {"verbose", 'v', 0, 0, N_("verbosely list files processed"), GRID+1 }, - {"checkpoint", CHECKPOINT_OPTION, N_("[.]NUMBER"), OPTION_ARG_OPTIONAL, + {"warning", WARNING_OPTION, N_("KEYWORD"), 0, + N_("warning control"), GRID+1 }, + {"checkpoint", CHECKPOINT_OPTION, N_("NUMBER"), OPTION_ARG_OPTIONAL, N_("display progress messages every NUMBERth record (default 10)"), GRID+1 }, + {"checkpoint-action", CHECKPOINT_ACTION_OPTION, N_("ACTION"), 0, + N_("execute ACTION on each checkpoint"), + GRID+1 }, {"check-links", 'l', 0, 0, N_("print a message if not all links are dumped"), GRID+1 }, {"totals", TOTALS_OPTION, N_("SIGNAL"), OPTION_ARG_OPTIONAL, @@ -834,6 +867,16 @@ exclude_vcs_files () "=RELEASE-ID", "=meta-update", "=update", + /* Bazaar */ + ".bzr", + ".bzrignore", + ".bzrtags", + /* Mercurial */ + ".hg", + ".hgignore", + ".hgtags", + /* darcs */ + "_darcs", NULL }; @@ -1014,6 +1057,9 @@ report_textual_dates (struct tar_args *args) static volatile int _argp_hang; +/* 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 */ @@ -1022,16 +1068,16 @@ enum read_file_list_state /* Result of reading file name from the list file */ file_list_skip /* Empty (zero-length) entry encountered, skip it */ }; -/* Read from FP a sequence of characters up to FILENAME_TERMINATOR and put them +/* 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) +read_name_from_file (FILE *fp, struct obstack *stk, int term) { int c; size_t counter = 0; - for (c = getc (fp); c != EOF && c != filename_terminator; c = getc (fp)) + for (c = getc (fp); c != EOF && c != term; c = getc (fp)) { if (c == 0) { @@ -1112,7 +1158,8 @@ update_argv (const char *filename, struct argp_state *state) 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; @@ -1126,7 +1173,8 @@ update_argv (const char *filename, struct argp_state *state) open_fatal (filename); } - while ((read_state = read_name_from_file (fp, &argv_stk)) != file_list_end) + while ((read_state = read_name_from_file (fp, &argv_stk, term)) + != file_list_end) { switch (read_state) { @@ -1141,8 +1189,9 @@ update_argv (const char *filename, struct argp_state *state) { size_t size; - WARN ((0, 0, N_("%s: file name read contains nul character"), - quotearg_colon (filename))); + 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); @@ -1155,7 +1204,7 @@ update_argv (const char *filename, struct argp_state *state) obstack_1grow (&argv_stk, 0); count = 1; /* Read rest of files using new filename terminator */ - filename_terminator = 0; + term = 0; break; } @@ -1172,7 +1221,7 @@ update_argv (const char *filename, struct argp_state *state) start = obstack_finish (&argv_stk); - if (filename_terminator == 0) + if (term == 0) for (p = start; *p; p += strlen (p) + 1) if (p[0] == '-') count++; @@ -1188,7 +1237,7 @@ update_argv (const char *filename, struct argp_state *state) for (i = state->next, p = start; *p; p += strlen (p) + 1, i++) { - if (filename_terminator == 0 && p[0] == '-') + if (term == 0 && p[0] == '-') state->argv[i++] = "--add-file"; state->argv[i] = p; } @@ -1237,6 +1286,10 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'a': args->compress_autodetect = true; break; + + case NO_AUTO_COMPRESS_OPTION: + args->compress_autodetect = false; + break; case 'b': { @@ -1308,6 +1361,10 @@ parse_opt (int key, char *arg, struct argp_state *state) dereference_option = true; break; + case HARD_DEREFERENCE_OPTION: + hard_dereference_option = true; + break; + case 'i': /* Ignore zero blocks (eofs). This can't be the default, because Unix tar writes two blocks of zeros, then pads out @@ -1316,16 +1373,14 @@ parse_opt (int key, char *arg, struct argp_state *state) ignore_zeros_option = true; break; - case 'I': - USAGE_ERROR ((0, 0, - _("Warning: the -I option is not supported;" - " perhaps you meant -j or -T?"))); - break; - case 'j': set_use_compress_program_option ("bzip2"); break; + case 'J': + set_use_compress_program_option ("xz"); + break; + case 'k': /* Don't replace existing files. */ old_files_option = KEEP_OLD_FILES; @@ -1333,7 +1388,7 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'K': starting_file_option = true; - addname (arg, 0); + addname (arg, 0, NULL); break; case ONE_FILE_SYSTEM_OPTION: @@ -1357,10 +1412,23 @@ parse_opt (int key, char *arg, struct argp_state *state) } break; + case LEVEL_OPTION: + { + char *p; + incremental_level = strtoul (arg, &p, 10); + if (*p) + USAGE_ERROR ((0, 0, _("Invalid incremental level value"))); + } + break; + case LZMA_OPTION: set_use_compress_program_option ("lzma"); break; + case LZOP_OPTION: + set_use_compress_program_option ("lzop"); + break; + case 'm': touch_option = true; break; @@ -1482,6 +1550,7 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'v': verbose_option++; + warning_option |= WARN_VERBOSE_WARNINGS; break; case 'V': @@ -1534,6 +1603,14 @@ parse_opt (int key, char *arg, struct argp_state *state) " on this platform"))); break; + case CHECK_DEVICE_OPTION: + check_device_option = true; + break; + + case NO_CHECK_DEVICE_OPTION: + check_device_option = false; + break; + case CHECKPOINT_OPTION: if (arg) { @@ -1541,7 +1618,7 @@ parse_opt (int key, char *arg, struct argp_state *state) if (*arg == '.') { - checkpoint_style = checkpoint_dot; + checkpoint_compile_action ("."); arg++; } checkpoint_option = strtoul (arg, &p, 0); @@ -1550,9 +1627,13 @@ parse_opt (int key, char *arg, struct argp_state *state) _("--checkpoint value is not an integer"))); } else - checkpoint_option = 10; + checkpoint_option = DEFAULT_CHECKPOINT; break; + case CHECKPOINT_ACTION_OPTION: + checkpoint_compile_action (arg); + break; + case BACKUP_OPTION: backup_option = true; if (arg) @@ -1690,6 +1771,10 @@ parse_opt (int key, char *arg, struct argp_state *state) filename_terminator = '\0'; break; + case NO_NULL_OPTION: + filename_terminator = '\n'; + break; + case NUMERIC_OWNER_OPTION: numeric_owner_option = true; break; @@ -1752,6 +1837,8 @@ parse_opt (int key, char *arg, struct argp_state *state) /* FIXME: What it is good for? */ same_permissions_option = true; same_order_option = true; + WARN ((0, 0, _("The --preserve option is deprecated, " + "use --preserve-permissions --preserve-order instead"))); break; case RECORD_SIZE_OPTION: @@ -1835,7 +1922,7 @@ parse_opt (int key, char *arg, struct argp_state *state) set_transform_expr (arg); break; - case USE_COMPRESS_PROGRAM_OPTION: + case 'I': set_use_compress_program_option (arg); break; @@ -1879,6 +1966,10 @@ parse_opt (int key, char *arg, struct argp_state *state) unquote_option = false; break; + case WARNING_OPTION: + set_warning_option (arg); + break; + case '0': case '1': case '2': @@ -2038,6 +2129,10 @@ decode_options (int argc, char **argv) owner_option = -1; group_option = -1; + check_device_option = true; + + incremental_level = -1; + /* Convert old-style tar call by exploding option element and rearranging options accordingly. */ @@ -2202,7 +2297,10 @@ decode_options (int argc, char **argv) && NEWER_OPTION_INITIALIZED (newer_mtime_option)) USAGE_ERROR ((0, 0, _("Cannot combine --listed-incremental with --newer"))); - + if (incremental_level != -1 && !listed_incremental_option) + WARN ((0, 0, + _("--level is meaningless without --listed-incremental"))); + if (volume_label_option) { if (archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT) @@ -2274,6 +2372,13 @@ decode_options (int argc, char **argv) else if (utc_option) verbose_option = 2; + if (tape_length_option && tape_length_option < record_size) + USAGE_ERROR ((0, 0, _("Volume length cannot be less than record size"))); + + if (same_order_option && listed_incremental_option) + USAGE_ERROR ((0, 0, _("--preserve-order is not compatible with " + "--listed-incremental"))); + /* Forbid using -c with no input files whatsoever. Check that `-f -', explicit or implied, is used correctly. */ @@ -2339,6 +2444,8 @@ decode_options (int argc, char **argv) backup_option = false; } + checkpoint_finish_compile (); + if (verbose_option) report_textual_dates (&args); } @@ -2374,11 +2481,14 @@ main (int argc, char **argv) obstack_init (&argv_stk); -#ifdef SIGCHLD + /* Ensure default behavior for some signals */ + signal (SIGPIPE, SIG_DFL); /* System V fork+wait does not work if SIGCHLD is ignored. */ signal (SIGCHLD, SIG_DFL); -#endif + /* Try to disable the ability to unlink a directory. */ + priv_set_remove_linkdir (); + /* Decode options. */ decode_options (argc, argv); @@ -2445,7 +2555,7 @@ main (int argc, char **argv) name_term (); if (exit_status == TAREXIT_FAILURE) - error (0, 0, _("Error exit delayed from previous errors")); + error (0, 0, _("Exiting with failure status due to previous errors")); if (stdlis == stdout) close_stdout ();