/* 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, 2009 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
#include <system.h>
#include <fnmatch.h>
-#include <getline.h>
#include <argp.h>
#include <argp-namefrob.h>
#include <argp-fmtstream.h>
#include <argmatch.h>
#include <closeout.h>
+#include <configmake.h>
#include <exitfail.h>
#include <getdate.h>
-#include <localedir.h>
#include <rmt.h>
+#include <rmt-command.h>
#include <prepargs.h>
#include <quotearg.h>
#include <version-etc.h>
#include <xstrtol.h>
#include <stdopen.h>
+#include <priv-set.h>
/* Local declarations. */
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,
+ 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,
IGNORE_FAILED_READ_OPTION,
INDEX_FILE_OPTION,
KEEP_NEWER_FILES_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,
TRANSFORM_OPTION,
UNQUOTE_OPTION,
USAGE_OPTION,
- USE_COMPRESS_PROGRAM_OPTION,
UTC_OPTION,
VERSION_OPTION,
VOLNO_FILE_OPTION,
const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION;
const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
-static char doc[] = N_("GNU `tar' saves many files together into a single tape or disk archive, and can restore individual files from the archive.\n\
+static char const doc[] = N_("\
+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\
tar -cf archive.tar foo bar # Create archive.tar from files foo and bar.\n\
tar -tvf archive.tar # List all files in archive.tar verbosely.\n\
- tar -xf archive.tar # Extract all files from archive.tar.\n\
-\vThe backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\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\
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\
/* NOTE:
- Available option letters are DEIJQY and aeqy. Consider the following
+ Available option letters are DEQY and eqy. Consider the following
assignments:
[For Solaris tar compatibility =/= Is it important at all?]
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 */
" 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
{NULL, 0, NULL, 0,
- N_("Overwrite control:"), GRID+1 },
+ N_("Overwrite control:"), GRID },
{"verify", 'W', 0, 0,
N_("attempt to verify the archive after writing it"), GRID+1 },
#define GRID 60
{NULL, 0, NULL, 0,
- N_("Device selection and switching:\n"), GRID+1 },
+ N_("Device selection and switching:"), GRID },
{"file", 'f', N_("ARCHIVE"), 0,
N_("use archive file or device ARCHIVE"), GRID+1 },
#define GRID 70
{NULL, 0, NULL, 0,
- N_("Device blocking:"), GRID+1 },
+ N_("Device blocking:"), GRID },
{"blocking-factor", 'b', N_("BLOCKS"), 0,
N_("BLOCKS x 512 bytes per record"), GRID+1 },
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 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 },
- {"use-compress-program", USE_COMPRESS_PROGRAM_OPTION, N_("PROG"), 0,
- N_("filter through PROG (must accept -d)"), 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 },
+ {"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
-
-#define GRID 90
+
+#define GRID 100
{NULL, 0, NULL, 0,
N_("Local file selection:"), GRID },
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,
{"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 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,
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,
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,
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 95
+#define GRID 120
{NULL, 0, NULL, 0,
N_("File name matching options (affect both exclude and include patterns):"),
GRID },
{"wildcards-match-slash", WILDCARDS_MATCH_SLASH_OPTION, 0, 0,
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,
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 },
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 },
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 */
};
+\f
#define MAKE_EXCL_OPTIONS(args) \
((((args)->wildcards != disable_wildcards) ? EXCLUDE_WILDCARDS : 0) \
| (args)->matching_flags \
| (args)->matching_flags \
| recursion_option)
-#ifdef REMOTE_SHELL
+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);
+}
+
+\f
+#ifdef REMOTE_SHELL
# define DECL_SHOW_DEFAULT_SETTINGS(stream, printer) \
{ \
printer (stream, \
static void
show_default_settings (FILE *fp)
DECL_SHOW_DEFAULT_SETTINGS(fp, fprintf)
-
+
static void
show_default_settings_fs (argp_fmtstream_t fs)
DECL_SHOW_DEFAULT_SETTINGS(fs, argp_fmtstream_printf)
{ "QUIT", SIGQUIT }
};
struct sigtab *p;
-
+
for (p = sigtab; p < sigtab + sizeof (sigtab) / sizeof (sigtab[0]); p++)
if (strcmp (p->name, name) == 0)
{
\f
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 */
file_list_end, /* End of list file */
- file_list_zero /* Zero separator encountered where it should not */
+ 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 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)
{
/* We have read a zero separator. The file possibly is
zero-separated */
- /* FATAL_ERROR((0, 0, N_("file name contains null character"))); */
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;
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;
open_fatal (filename);
}
- while ((read_state = read_name_from_file (fp, &argv_stk)) == file_list_success)
- count++;
-
- if (read_state == file_list_zero)
+ while ((read_state = read_name_from_file (fp, &argv_stk, term))
+ != file_list_end)
{
- size_t size;
+ switch (read_state)
+ {
+ case file_list_success:
+ count++;
+ break;
- WARN ((0, 0, N_("%s: file name read contains nul character"),
- quotearg_colon (filename)));
+ case file_list_end: /* won't happen, just to pacify gcc */
+ break;
- /* 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 */
- filename_terminator = 0;
- while (read_name_from_file (fp, &argv_stk) == file_list_success)
- count++;
+ case file_list_zero:
+ {
+ size_t size;
+
+ WARN ((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)
start = obstack_finish (&argv_stk);
- if (filename_terminator == 0)
+ if (term == 0)
for (p = start; *p; p += strlen (p) + 1)
if (p[0] == '-')
count++;
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;
}
ARGP_HELP_STD_HELP & ~ARGP_HELP_BUG_ADDR);
/* FIXME: use struct uparams.rmargin (from argp-help.c) instead of 79 */
fs = argp_make_fmtstream (state->out_stream, 0, 79, 0);
-
+
argp_fmtstream_printf (fs, "\n%s\n\n",
_("Valid arguments for --quoting-style options are:"));
tar_list_quoting_styles (fs, " ");
-
+
argp_fmtstream_puts (fs, _("\n*This* tar defaults to:\n"));
show_default_settings_fs (fs);
argp_fmtstream_putc (fs, '\n');
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 NO_AUTO_COMPRESS_OPTION:
+ args->compress_autodetect = false;
+ break;
+
case 'b':
{
uintmax_t u;
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
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;
}
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;
get_date_or_file (args, "--mtime", arg, &mtime_option);
set_mtime_option = true;
break;
-
+
case 'n':
seekable_archive = true;
break;
}
}
break;
-
+
case 't':
set_subcommand_option (LIST_SUBCOMMAND);
verbose_option++;
" 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)
{
if (*arg == '.')
{
- checkpoint_style = checkpoint_dot;
+ checkpoint_compile_action (".");
arg++;
}
checkpoint_option = strtoul (arg, &p, 0);
_("--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)
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_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:
force_local_option = true;
break;
filename_terminator = '\0';
break;
+ case NO_NULL_OPTION:
+ filename_terminator = '\n';
+ break;
+
case NUMERIC_OWNER_OPTION:
numeric_owner_option = true;
break;
/* 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:
case TRANSFORM_OPTION:
set_transform_expr (arg);
break;
-
- case USE_COMPRESS_PROGRAM_OPTION:
+
+ case 'I':
set_use_compress_program_option (arg);
break;
/* 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. */
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;
unquote_option = true;
tar_sparse_major = 1;
tar_sparse_minor = 0;
-
+
owner_option = -1;
group_option = -1;
+ check_device_option = true;
+
/* Convert old-style tar call by exploding option element and rearranging
options accordingly. */
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);
}
/* 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;
}
/* Warn about implicit use of the wildcards in command line arguments.
See TODO */
warn_regex_usage = args.wildcards == default_wildcards;
-
+
/* Derive option values and check option consistency. */
if (archive_format == DEFAULT_FORMAT)
| FORMAT_MASK (GNU_FORMAT)
| FORMAT_MASK (POSIX_FORMAT));
- if (multi_volume_option
- && archive_format == POSIX_FORMAT
- && subcommand_option == CREATE_SUBCOMMAND
- && !tape_length_option)
- USAGE_ERROR ((0, 0,
- _("creating multi-volume archives in posix format requires using --tape-length (-L) option")));
-
if (occurrence_option)
{
if (!args.input_files)
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. */
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:
break;
}
+ /* Initialize stdlis */
+ if (index_file_name)
+ {
+ stdlis = fopen (index_file_name, "w");
+ if (! stdlis)
+ open_error (index_file_name);
+ }
+ else
+ stdlis = to_stdout_option ? stderr : stdout;
+
archive_name_cursor = archive_name_array;
/* Prepare for generating backup names. */
backup_option = false;
}
+ checkpoint_finish_compile ();
+
if (verbose_option)
report_textual_dates (&args);
}
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);
+
name_init ();
/* Main command execution. */
free (archive_name_array);
name_term ();
+ if (exit_status == TAREXIT_FAILURE)
+ error (0, 0, _("Exiting with failure status due to previous errors"));
+
if (stdlis == stdout)
close_stdout ();
-
- if (exit_status == TAREXIT_FAILURE)
- error (0, 0, _("Error exit delayed from previous errors"));
- if (ferror (stderr) || fclose (stderr) != 0)
+ else if (ferror (stderr) || fclose (stderr) != 0)
exit_status = TAREXIT_FAILURE;
+
return exit_status;
}
free (st->gname);
free (st->sparse_map);
free (st->dumpdir);
+ xheader_destroy (&st->xhdr);
memset (st, 0, sizeof (*st));
}