]> git.ipfire.org Git - thirdparty/tar.git/commitdiff
Report positional options that were used but had no effect during archive creation
authorSergey Poznyakoff <gray@gnu.org.ua>
Fri, 27 May 2016 07:39:49 +0000 (10:39 +0300)
committerSergey Poznyakoff <gray@gnu.org.ua>
Fri, 27 May 2016 08:50:19 +0000 (11:50 +0300)
* 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.

NEWS
configure.ac
doc/tar.texi
src/names.c
tests/Makefile.am
tests/positional01.at [new file with mode: 0644]
tests/positional02.at [new file with mode: 0644]
tests/positional03.at [new file with mode: 0644]
tests/testsuite.at

diff --git a/NEWS b/NEWS
index 501164abd0ef306b113cc2ce9ab5253365093fc2..caa77bc1f7ddefd73fbb528bfdaeccf6947f42de 100644 (file)
--- a/NEWS
+++ b/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>
 
+\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
 
index 50fbae512725d0711fbaeb566c33d0a25740636c..715a36610cc47bf418d8d6fd977796314c562661 100644 (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])
index a8969e088120133e910a37bd5936664876c6fbe4..51ed159bf538f4359f1925529f65e8cd273e9ff8 100644 (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
index 037b869d7596c9c44476d28aca72acf46c8851c6..e3be75693d135cbb4a3a77f2a2ec1f780d1052ca 100644 (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;
 }  
 \f
 /* 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;
 }
+\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)
 {
@@ -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;
 }
 
index 3e9427692ff7dfdbb1312ff5320449c3be7fc6dd..0ea6d1725db8a7335f40f19bc4c1b99be94c25cb 100644 (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\
diff --git a/tests/positional01.at b/tests/positional01.at
new file mode 100644 (file)
index 0000000..37b14db
--- /dev/null
@@ -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
+
diff --git a/tests/positional02.at b/tests/positional02.at
new file mode 100644 (file)
index 0000000..352b62c
--- /dev/null
@@ -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
+
diff --git a/tests/positional03.at b/tests/positional03.at
new file mode 100644 (file)
index 0000000..9a03671
--- /dev/null
@@ -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
+
index cf4b2fd547b9537dc2bf7456d7e446c5bba53f93..11c39c9f690efcf46379ea05bc8337106a85b5c7 100644 (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])