X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Ftar.c;h=67bb0be7816eed29dabfea111e8f33aa2f79c24f;hb=c1b55e02b1f12f835ac17ae58b50d440df663f7f;hp=e21a6466f40249ff530ffed978ebc053d43f6b8e;hpb=ca856c2585cbb2e0ca6774c23a0f53447dbf3bf7;p=chaz%2Ftar diff --git a/src/tar.c b/src/tar.c index e21a646..67bb0be 100644 --- a/src/tar.c +++ b/src/tar.c @@ -7,7 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any later + Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -250,8 +249,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, @@ -260,6 +262,7 @@ enum EXCLUDE_TAG_OPTION, EXCLUDE_TAG_UNDER_OPTION, EXCLUDE_TAG_ALL_OPTION, + EXCLUDE_VCS_OPTION, FORCE_LOCAL_OPTION, GROUP_OPTION, HANG_OPTION, @@ -272,6 +275,8 @@ enum 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, @@ -345,7 +350,7 @@ The version control may be set with --backup or VERSION_CONTROL, values are:\n\n /* NOTE: - Available option letters are DEIJQY and aeqy. Consider the following + Available option letters are DEIQY and eqy. Consider the following assignments: [For Solaris tar compatibility =/= Is it important at all?] @@ -408,6 +413,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 @@ -574,20 +585,32 @@ static struct argp_option options[] = { N_("control pax keywords"), GRID+8 }, {"label", 'V', N_("TEXT"), 0, N_("create archive with volume name TEXT; at list/extract time, use TEXT as a globbing pattern for volume name"), GRID+8 }, +#undef GRID + +#define GRID 90 + {NULL, 0, NULL, 0, + 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 use archive suffix to determine the compression program"), + GRID+1 }, {"bzip2", 'j', 0, 0, - N_("filter the archive through bzip2"), GRID+8 }, + N_("filter the archive through bzip2"), GRID+1 }, {"gzip", 'z', 0, 0, - N_("filter the archive through gzip"), GRID+8 }, - {"gunzip", 0, 0, OPTION_ALIAS, NULL, GRID+8 }, - {"ungzip", 0, 0, OPTION_ALIAS, NULL, GRID+8 }, + N_("filter the archive through gzip"), GRID+1 }, + {"gunzip", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, + {"ungzip", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, {"compress", 'Z', 0, 0, - N_("filter the archive through compress"), GRID+8 }, - {"uncompress", 0, 0, OPTION_ALIAS, NULL, GRID+8 }, + N_("filter the archive through compress"), GRID+1 }, + {"uncompress", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, + {"lzma", 'J', 0, 0, + N_("filter the archive through lzma"), GRID+1 }, {"use-compress-program", USE_COMPRESS_PROGRAM_OPTION, N_("PROG"), 0, - N_("filter through PROG (must accept -d)"), GRID+8 }, + N_("filter through PROG (must accept -d)"), GRID+1 }, #undef GRID - -#define GRID 90 + +#define GRID 100 {NULL, 0, NULL, 0, N_("Local file selection:"), GRID }, @@ -622,6 +645,8 @@ static struct argp_option options[] = { N_("exclude everything under directories containing FILE"), GRID+1 }, {"exclude-tag-all", EXCLUDE_TAG_ALL_OPTION, N_("FILE"), 0, N_("exclude directories containing FILE"), GRID+1 }, + {"exclude-vcs", EXCLUDE_VCS_OPTION, NULL, 0, + N_("exclude version control system directories"), GRID+1 }, {"no-recursion", NO_RECURSION_OPTION, 0, 0, N_("avoid descending automatically in directories"), GRID+1 }, {"one-file-system", ONE_FILE_SYSTEM_OPTION, 0, 0, @@ -632,6 +657,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, @@ -645,7 +672,7 @@ static struct argp_option options[] = { N_("backup before removal, override usual suffix ('~' unless overridden by environment variable SIMPLE_BACKUP_SUFFIX)"), GRID+1 }, #undef GRID -#define GRID 92 +#define GRID 110 {NULL, 0, NULL, 0, N_("File name transformations:"), GRID }, {"strip-components", STRIP_COMPONENTS_OPTION, N_("NUMBER"), 0, @@ -655,7 +682,7 @@ static struct argp_option options[] = { N_("use sed replace EXPRESSION to transform file names"), GRID+1 }, #undef GRID -#define GRID 95 +#define GRID 120 {NULL, 0, NULL, 0, N_("File name matching options (affect both exclude and include patterns):"), GRID }, @@ -677,15 +704,18 @@ static struct argp_option options[] = { N_("wildcards match `/' (default for exclusion)"), GRID+1 }, #undef GRID -#define GRID 100 +#define GRID 130 {NULL, 0, NULL, 0, N_("Informative output:"), GRID }, {"verbose", 'v', 0, 0, N_("verbosely list files processed"), GRID+1 }, - {"checkpoint", CHECKPOINT_OPTION, N_("[.]NUMBER"), OPTION_ARG_OPTIONAL, + {"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, @@ -718,7 +748,7 @@ static struct argp_option options[] = { N_("disable quoting for characters from STRING"), GRID+1 }, #undef GRID -#define GRID 110 +#define GRID 140 {NULL, 0, NULL, 0, N_("Compatibility options:"), GRID }, @@ -726,7 +756,7 @@ static struct argp_option options[] = { N_("when creating, same as --old-archive; when extracting, same as --no-same-owner"), GRID+1 }, #undef GRID -#define GRID 120 +#define GRID 150 {NULL, 0, NULL, 0, N_("Other options:"), GRID }, @@ -783,8 +813,11 @@ struct tar_args /* Variables used during option parsing */ char const *backup_suffix_string; /* --suffix option argument */ char const *version_control_string; /* --backup option argument */ bool input_files; /* True if some input files where given */ + int compress_autodetect; /* True if compression autodetection should + be attempted when creating archives */ }; + #define MAKE_EXCL_OPTIONS(args) \ ((((args)->wildcards != disable_wildcards) ? EXCLUDE_WILDCARDS : 0) \ | (args)->matching_flags \ @@ -796,6 +829,47 @@ struct tar_args /* Variables used during option parsing */ | (args)->matching_flags \ | recursion_option) +void +exclude_vcs_files () +{ + int i; + static char *vcs_file[] = { + /* CVS: */ + "CVS", + ".cvsignore", + /* RCS: */ + "RCS", + /* SCCS: */ + "SCCS", + /* SVN: */ + ".svn", + /* git: */ + ".git", + ".gitignore", + /* Arch: */ + ".arch-ids", + "{arch}", + "=RELEASE-ID", + "=meta-update", + "=update", + /* Bazaar */ + ".bzr", + ".bzrignore", + ".bzrtags", + /* Mercurial */ + ".hg", + ".hgignore", + ".hgtags", + /* darcs */ + "_darcs", + NULL + }; + + for (i = 0; vcs_file[i]; i++) + add_exclude (excluded, vcs_file[i], 0); +} + + #ifdef REMOTE_SHELL # define DECL_SHOW_DEFAULT_SETTINGS(stream, printer) \ { \ @@ -968,6 +1042,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 */ @@ -1188,6 +1265,14 @@ parse_opt (int key, char *arg, struct argp_state *state) set_subcommand_option (CAT_SUBCOMMAND); break; + case 'a': + args->compress_autodetect = true; + break; + + case NO_AUTO_COMPRESS_OPTION: + args->compress_autodetect = false; + break; + case 'b': { uintmax_t u; @@ -1258,6 +1343,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 @@ -1276,6 +1365,10 @@ parse_opt (int key, char *arg, struct argp_state *state) set_use_compress_program_option ("bzip2"); break; + case 'J': + set_use_compress_program_option ("lzma"); + break; + case 'k': /* Don't replace existing files. */ old_files_option = KEEP_OLD_FILES; @@ -1480,6 +1573,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) { @@ -1487,7 +1588,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); @@ -1496,9 +1597,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) @@ -1548,6 +1653,10 @@ parse_opt (int key, char *arg, struct argp_state *state) add_exclusion_tag (arg, exclusion_tag_all, NULL); break; + case EXCLUDE_VCS_OPTION: + exclude_vcs_files (); + break; + case FORCE_LOCAL_OPTION: force_local_option = true; break; @@ -1934,23 +2043,23 @@ usage (int status) /* Parse the options for tar. */ static struct argp_option * -find_argp_option (struct argp_option *options, int letter) +find_argp_option (struct argp_option *o, int letter) { for (; - !(options->name == NULL - && options->key == 0 - && options->arg == 0 - && options->flags == 0 - && options->doc == NULL); options++) - if (options->key == letter) - return options; + !(o->name == NULL + && o->key == 0 + && o->arg == 0 + && o->flags == 0 + && o->doc == NULL); o++) + if (o->key == letter) + return o; return NULL; } static void decode_options (int argc, char **argv) { - int index; + int idx; struct tar_args args; /* Set some default option values. */ @@ -1963,7 +2072,8 @@ decode_options (int argc, char **argv) args.backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); args.version_control_string = 0; args.input_files = false; - + args.compress_autodetect = false; + subcommand_option = UNKNOWN_SUBCOMMAND; archive_format = DEFAULT_FORMAT; blocking_factor = DEFAULT_BLOCKING; @@ -1979,6 +2089,8 @@ decode_options (int argc, char **argv) owner_option = -1; group_option = -1; + check_device_option = true; + /* Convert old-style tar call by exploding option element and rearranging options accordingly. */ @@ -2041,7 +2153,7 @@ decode_options (int argc, char **argv) prepend_default_options (getenv ("TAR_OPTIONS"), &argc, &argv); if (argp_parse (&argp, argc, argv, ARGP_IN_ORDER|ARGP_NO_HELP, - &index, &args)) + &idx, &args)) exit (TAREXIT_FAILURE); @@ -2069,9 +2181,9 @@ decode_options (int argc, char **argv) } /* Handle operands after any "--" argument. */ - for (; index < argc; index++) + for (; idx < argc; idx++) { - name_add_name (argv[index], MAKE_INCL_OPTIONS (&args)); + name_add_name (argv[idx], MAKE_INCL_OPTIONS (&args)); args.input_files = true; } @@ -2215,6 +2327,9 @@ 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"))); + /* Forbid using -c with no input files whatsoever. Check that `-f -', explicit or implied, is used correctly. */ @@ -2224,6 +2339,10 @@ decode_options (int argc, char **argv) if (!args.input_files && !files_from_option) USAGE_ERROR ((0, 0, _("Cowardly refusing to create an empty archive"))); + if (args.compress_autodetect && archive_names + && strcmp (archive_name_array[0], "-")) + set_comression_program_by_suffix (archive_name_array[0], + use_compress_program_option); break; case EXTRACT_SUBCOMMAND: @@ -2276,6 +2395,8 @@ decode_options (int argc, char **argv) backup_option = false; } + checkpoint_finish_compile (); + if (verbose_option) report_textual_dates (&args); } @@ -2382,7 +2503,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 (); @@ -2408,6 +2529,7 @@ tar_stat_destroy (struct tar_stat_info *st) free (st->gname); free (st->sparse_map); free (st->dumpdir); + xheader_destroy (&st->xhdr); memset (st, 0, sizeof (*st)); }