X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2Ftar.c;h=f3228e146c79ebcb9037a86e48599bfe5a8f3131;hb=ec4741d732fa5a37b245f3b27e4dadea9f2fe3b7;hp=35121ff28430bcd7f776c67427bf19e7cd0cb62d;hpb=137ebf41fd97baa7e4f2a66e0da0bdb182ca6f7b;p=chaz%2Ftar diff --git a/src/tar.c b/src/tar.c index 35121ff..f3228e1 100644 --- a/src/tar.c +++ b/src/tar.c @@ -1,13 +1,13 @@ /* A tar (tape archiver) program. Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, - 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2001, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by John Gilmore, starting 1985-08-25. 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 @@ -251,11 +250,18 @@ enum ATIME_PRESERVE_OPTION, BACKUP_OPTION, CHECKPOINT_OPTION, + CHECKPOINT_ACTION_OPTION, DELAY_DIRECTORY_RESTORE_OPTION, + HARD_DEREFERENCE_OPTION, DELETE_OPTION, EXCLUDE_CACHES_OPTION, + EXCLUDE_CACHES_UNDER_OPTION, + EXCLUDE_CACHES_ALL_OPTION, EXCLUDE_OPTION, EXCLUDE_TAG_OPTION, + EXCLUDE_TAG_UNDER_OPTION, + EXCLUDE_TAG_ALL_OPTION, + EXCLUDE_VCS_OPTION, FORCE_LOCAL_OPTION, GROUP_OPTION, HANG_OPTION, @@ -264,6 +270,7 @@ enum IGNORE_FAILED_READ_OPTION, INDEX_FILE_OPTION, KEEP_NEWER_FILES_OPTION, + LZMA_OPTION, MODE_OPTION, MTIME_OPTION, NEWER_MTIME_OPTION, @@ -341,7 +348,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 DEIJQY and eqy. Consider the following assignments: [For Solaris tar compatibility =/= Is it important at all?] @@ -570,20 +577,29 @@ 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 }, {"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", LZMA_OPTION, 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 }, @@ -604,9 +620,22 @@ static struct argp_option options[] = { {"exclude-from", 'X', N_("FILE"), 0, N_("exclude patterns listed in FILE"), GRID+1 }, {"exclude-caches", EXCLUDE_CACHES_OPTION, 0, 0, - N_("exclude directories containing a cache tag"), GRID+1 }, + N_("exclude contents of directories containing CACHEDIR.TAG, " + "except for the tag file itself"), GRID+1 }, + {"exclude-caches-under", EXCLUDE_CACHES_UNDER_OPTION, 0, 0, + N_("exclude everything under directories containing CACHEDIR.TAG"), + GRID+1 }, + {"exclude-caches-all", EXCLUDE_CACHES_ALL_OPTION, 0, 0, + N_("exclude directories containing CACHEDIR.TAG"), GRID+1 }, {"exclude-tag", EXCLUDE_TAG_OPTION, N_("FILE"), 0, - N_("exclude directories containing FILE"), GRID+1 }, + N_("exclude contents of directories containing FILE, except" + " for FILE itself"), GRID+1 }, + {"exclude-tag-under", EXCLUDE_TAG_UNDER_OPTION, N_("FILE"), 0, + 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, @@ -617,6 +646,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, @@ -630,7 +661,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, @@ -640,7 +671,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 }, @@ -662,15 +693,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, @@ -703,7 +737,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 }, @@ -711,7 +745,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 }, @@ -768,8 +802,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 \ @@ -781,6 +818,37 @@ 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", + 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) \ { \ @@ -1163,16 +1231,20 @@ parse_opt (int key, char *arg, struct argp_state *state) switch (key) { - case ARGP_KEY_ARG: - /* File name or non-parsed option, because of ARGP_IN_ORDER */ - name_add_name (arg, MAKE_INCL_OPTIONS (args)); - args->input_files = true; - break; + case ARGP_KEY_ARG: + /* File name or non-parsed option, because of ARGP_IN_ORDER */ + name_add_name (arg, MAKE_INCL_OPTIONS (args)); + args->input_files = true; + break; case 'A': set_subcommand_option (CAT_SUBCOMMAND); break; + case 'a': + args->compress_autodetect = true; + break; + case 'b': { uintmax_t u; @@ -1243,6 +1315,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 @@ -1292,6 +1368,10 @@ parse_opt (int key, char *arg, struct argp_state *state) } break; + case LZMA_OPTION: + set_use_compress_program_option ("lzma"); + break; + case 'm': touch_option = true; break; @@ -1472,7 +1552,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); @@ -1481,9 +1561,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) @@ -1507,11 +1591,34 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case EXCLUDE_CACHES_OPTION: - exclude_caches_option = true; + add_exclusion_tag ("CACHEDIR.TAG", exclusion_tag_contents, + cachedir_file_p); + break; + + case EXCLUDE_CACHES_UNDER_OPTION: + add_exclusion_tag ("CACHEDIR.TAG", exclusion_tag_under, + cachedir_file_p); + break; + + case EXCLUDE_CACHES_ALL_OPTION: + add_exclusion_tag ("CACHEDIR.TAG", exclusion_tag_all, + cachedir_file_p); break; case EXCLUDE_TAG_OPTION: - add_exclude_tag (arg); + add_exclusion_tag (arg, exclusion_tag_contents, NULL); + break; + + case EXCLUDE_TAG_UNDER_OPTION: + add_exclusion_tag (arg, exclusion_tag_under, NULL); + break; + + case EXCLUDE_TAG_ALL_OPTION: + add_exclusion_tag (arg, exclusion_tag_all, NULL); + break; + + case EXCLUDE_VCS_OPTION: + exclude_vcs_files (); break; case FORCE_LOCAL_OPTION: @@ -1900,23 +2007,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. */ @@ -1929,7 +2036,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; @@ -2007,7 +2115,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); @@ -2035,9 +2143,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; } @@ -2190,6 +2298,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: @@ -2242,6 +2354,8 @@ decode_options (int argc, char **argv) backup_option = false; } + checkpoint_finish_compile (); + if (verbose_option) report_textual_dates (&args); } @@ -2268,9 +2382,6 @@ main (int argc, char **argv) /* Make sure we have first three descriptors available */ stdopen (); - /* Close all inherited open descriptors, except for the first three */ - closeopen (); - /* Pre-allocate a few structures. */ allocated_archive_names = 10; @@ -2288,6 +2399,7 @@ main (int argc, char **argv) /* Decode options. */ decode_options (argc, argv); + name_init (); /* Main command execution. */ @@ -2376,6 +2488,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)); }