Report positional options that were used but had no effect during archive creation
* src/names.c (file_selection_option) (file_selection_option_name): New functions. (unconsumed_option_push, unconsumed_option_free) (unconsumed_option_report): New functions. (name_list_advance): Maintain a list of eventually unconsumed options during archive creation. Report unconsumed options, if any. * tests/positional01.at: New test case. * tests/positional02.at: New test case. * tests/positional03.at: New test case. * tests/Makefile.am: Add new test cases. * tests/testsuite.at: Likewise. * NEWS: Document the changes. * configure.ac: Version 1.29.90 * doc/tar.texi: Document the changes.
This commit is contained in:
24
NEWS
24
NEWS
@@ -1,6 +1,28 @@
|
||||
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>
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
version 1.29 - Sergey Poznyakoff, 2016-05-16
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# 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])
|
||||
|
||||
17
doc/tar.texi
17
doc/tar.texi
@@ -3879,6 +3879,23 @@ tar -cf a.tar /usr --no-recursion /var/*
|
||||
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
|
||||
|
||||
114
src/names.c
114
src/names.c
@@ -149,16 +149,29 @@ static struct argp_option names_options[] = {
|
||||
{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;
|
||||
}
|
||||
|
||||
/* Either NL or NUL, as decided by the --null option. */
|
||||
@@ -670,7 +683,85 @@ name_list_adjust (void)
|
||||
while (name_head->prev)
|
||||
name_head = name_head->prev;
|
||||
}
|
||||
|
||||
/* 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 ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
name_list_advance (void)
|
||||
{
|
||||
@@ -678,7 +769,18 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1013,6 +1115,8 @@ name_next_elt (int change_dirs)
|
||||
}
|
||||
}
|
||||
|
||||
unconsumed_option_report ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +166,9 @@ TESTSUITE_AT = \
|
||||
opcomp04.at\
|
||||
opcomp05.at\
|
||||
opcomp06.at\
|
||||
positional01.at\
|
||||
positional02.at\
|
||||
positional03.at\
|
||||
options.at\
|
||||
options02.at\
|
||||
owner.at\
|
||||
|
||||
54
tests/positional01.at
Normal file
54
tests/positional01.at
Normal file
@@ -0,0 +1,54 @@
|
||||
# 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
|
||||
|
||||
49
tests/positional02.at
Normal file
49
tests/positional02.at
Normal file
@@ -0,0 +1,49 @@
|
||||
# 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
|
||||
|
||||
47
tests/positional03.at
Normal file
47
tests/positional03.at
Normal file
@@ -0,0 +1,47 @@
|
||||
# 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
|
||||
|
||||
@@ -213,6 +213,11 @@ m4_include([opcomp04.at])
|
||||
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])
|
||||
|
||||
Reference in New Issue
Block a user