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:
Sergey Poznyakoff
2016-05-27 10:39:49 +03:00
parent 20b55f0679
commit 9a33077a7b
9 changed files with 308 additions and 7 deletions

24
NEWS
View File

@@ -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

View File

@@ -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])

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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
View 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
View 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
View 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

View File

@@ -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])