-GNU tar NEWS - User visible changes. 2016-05-16
+GNU tar NEWS - User visible changes. 2016-05-27
Please send GNU tar bug reports to <bug-tar@gnu.org>
+\f
+version 1.29.90 (Git)
+
+* Report erroneous use of positional options.
+
+During archive creation or update, tar keeps track of positional
+options (see the manual, subsection 3.4.4 "Position-Sensitive
+Options"), and reports those that had no effect. For example, when
+invoked as
+
+ tar -cf a.tar . --exclude '*.o'
+
+tar will create the archive, but will exit with status 2, having
+issued the following error message
+
+ tar: The following options were used after any non-optional
+ arguments in archive create or update mode. These options are
+ positional and affect only arguments that follow them. Please,
+ rearrange them properly.
+ tar: --exclude '*.o' has no effect
+ tar: Exiting with failure status due to previous errors
+
\f
version 1.29 - Sergey Poznyakoff, 2016-05-16
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-AC_INIT([GNU tar], [1.29], [bug-tar@gnu.org])
+AC_INIT([GNU tar], [1.29.90], [bug-tar@gnu.org])
AC_CONFIG_SRCDIR([src/tar.c])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
tar -cf a.tar --recursion /usr --no-recursion /var/*
@end example
+During archive creation, @GNUTAR{} keeps track of positional options
+used and arguments affected by them. If it finds out that any such
+options are used in an obviously erroneous way, the fact is reported
+and exit code is set to 2. E.g.:
+
+@example
+@group
+$ @kbd{tar -cf a.tar . --exclude '*.o'}
+tar: The following options were used after any non-optional
+arguments in archive create or update mode. These options are
+positional and affect only arguments that follow them. Please,
+rearrange them properly.
+tar: --exclude '*.o' has no effect
+tar: Exiting with failure status due to previous errors
+@end group
+@end example
+
The following table summarizes all position-sensitive options.
@table @option
{NULL}
};
-static bool
-is_file_selection_option (int key)
+static struct argp_option const *
+file_selection_option (int key)
{
struct argp_option *p;
for (p = names_options;
!(p->name == NULL && p->key == 0 && p->doc == NULL); p++)
if (p->key == key)
- return true;
- return false;
+ return p;
+ return NULL;
+}
+
+static char const *
+file_selection_option_name (int key)
+{
+ struct argp_option const *opt = file_selection_option (key);
+ return opt ? opt->name : NULL;
+}
+
+static bool
+is_file_selection_option (int key)
+{
+ return file_selection_option (key) != NULL;
}
\f
/* Either NL or NUL, as decided by the --null option. */
while (name_head->prev)
name_head = name_head->prev;
}
+\f
+/* For error-reporting purposes, keep a doubly-linked list of unconsumed file
+ selection options. The option is deemed unconsumed unless followed by one
+ or more file/member name arguments. When archive creation is requested,
+ each file selection option encountered is pushed into the list. The list
+ is cleared upon encountering a file name argument.
+
+ If the list is not empty when all arguments have been processed, an error
+ message is issued reporting the options that had no effect.
+
+ For simplicity, only a tail pointer of the list is maintained.
+*/
+
+struct name_elt *unconsumed_option_tail;
+
+/* Push an option to the list */
+static void
+unconsumed_option_push (struct name_elt *elt)
+{
+ elt->prev = unconsumed_option_tail;
+ if (unconsumed_option_tail)
+ unconsumed_option_tail->next = elt;
+ unconsumed_option_tail = elt;
+}
+
+/* Clear the unconsumed option list */
+static void
+unconsumed_option_free (void)
+{
+ while (unconsumed_option_tail)
+ {
+ struct name_elt *elt = unconsumed_option_tail;
+ unconsumed_option_tail = unconsumed_option_tail->prev;
+ free (elt);
+ }
+}
+
+/* Report any options that have not been consumed */
+static void
+unconsumed_option_report (void)
+{
+ if (unconsumed_option_tail)
+ {
+ struct name_elt *elt;
+
+ ERROR ((0, 0, _("The following options were used after any non-optional arguments in archive create or update mode. These options are positional and affect only arguments that follow them. Please, rearrange them properly.")));
+
+ elt = unconsumed_option_tail;
+ while (elt->prev)
+ elt = elt->prev;
+ while (elt)
+ {
+ switch (elt->type)
+ {
+ case NELT_CHDIR:
+ ERROR ((0, 0, _("-C %s has no effect"), quote (elt->v.name)));
+ break;
+
+ case NELT_OPTION:
+ if (elt->v.opt.arg)
+ ERROR ((0, 0, _("--%s %s has no effect"),
+ file_selection_option_name (elt->v.opt.option),
+ quote (elt->v.opt.arg)));
+ else
+ ERROR ((0, 0, _("--%s has no effect"),
+ file_selection_option_name (elt->v.opt.option)));
+ break;
+
+ default:
+ break;
+ }
+ elt = elt->next;
+ }
+
+ unconsumed_option_free ();
+ }
+}
+\f
static void
name_list_advance (void)
{
name_head = elt->next;
if (name_head)
name_head->prev = NULL;
- free (elt);
+ if (elt->type == NELT_OPTION || elt->type == NELT_CHDIR)
+ {
+ if (subcommand_option == CREATE_SUBCOMMAND
+ || subcommand_option == UPDATE_SUBCOMMAND)
+ unconsumed_option_push (elt);
+ }
+ else
+ {
+ if (elt->type != NELT_NOOP)
+ unconsumed_option_free ();
+ free (elt);
+ }
}
}
}
+ unconsumed_option_report ();
+
return NULL;
}
opcomp04.at\
opcomp05.at\
opcomp06.at\
+ positional01.at\
+ positional02.at\
+ positional03.at\
options.at\
options02.at\
owner.at\
--- /dev/null
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This file is part of GNU tar.
+
+# GNU tar 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 3 of the License, or
+# (at your option) any later version.
+
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Exclude])
+AT_KEYWORDS([options positional positional01 exclude])
+
+AT_CHECK([
+AT_SORT_PREREQ
+mkdir dir
+> dir/A.a
+> dir/B.a
+> dir/A.b
+tar -cf a.tar --exclude '*.b' dir
+echo $?
+tar -tf a.tar | sort
+tar -cf a.tar dir --exclude '*.b'
+echo $?
+tar -tf a.tar | sort
+],
+[0],
+[0
+dir/
+dir/A.a
+dir/B.a
+2
+dir/
+dir/A.a
+dir/A.b
+dir/B.a
+],
+[tar: The following options were used after any non-optional arguments in archive create or update mode. These options are positional and affect only arguments that follow them. Please, rearrange them properly.
+tar: --exclude '*.b' has no effect
+tar: Exiting with failure status due to previous errors
+])
+
+AT_CLEANUP
+
--- /dev/null
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This file is part of GNU tar.
+
+# GNU tar 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 3 of the License, or
+# (at your option) any later version.
+
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Directory])
+AT_KEYWORDS([options positional positional02 directory chdir])
+
+AT_CHECK([
+AT_SORT_PREREQ
+mkdir dir
+> dir/A.a
+> dir/B.a
+> dir/A.b
+tar -cf a.tar -C dir .
+echo $?
+tar -tf a.tar | sort
+tar -cf a.tar . -C dir
+],
+[2],
+[0
+./
+./A.a
+./A.b
+./B.a
+],
+[tar: ./a.tar: file is the archive; not dumped
+tar: The following options were used after any non-optional arguments in archive create or update mode. These options are positional and affect only arguments that follow them. Please, rearrange them properly.
+tar: -C 'dir' has no effect
+tar: Exiting with failure status due to previous errors
+])
+
+AT_CLEANUP
+
--- /dev/null
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This file is part of GNU tar.
+
+# GNU tar 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 3 of the License, or
+# (at your option) any later version.
+
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Several options])
+AT_KEYWORDS([options positional positional03])
+
+AT_CHECK([
+AT_SORT_PREREQ
+mkdir t
+cd t
+mkdir dir
+> dir/A.a
+> dir/B.a
+> dir/A.b
+tar -vcf ../a.tar --exclude '*.b' . -C dir --exclude '*.c' | sort
+],
+[0],
+[./
+./dir/
+./dir/A.a
+./dir/B.a
+],
+[tar: The following options were used after any non-optional arguments in archive create or update mode. These options are positional and affect only arguments that follow them. Please, rearrange them properly.
+tar: -C 'dir' has no effect
+tar: --exclude '*.c' has no effect
+tar: Exiting with failure status due to previous errors
+])
+
+AT_CLEANUP
+
m4_include([opcomp05.at])
m4_include([opcomp06.at])
+AT_BANNER([Positional options])
+m4_include([positional01.at])
+m4_include([positional02.at])
+m4_include([positional03.at])
+
AT_BANNER([The -T option])
m4_include([T-mult.at])
m4_include([T-nest.at])