ソースを参照

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.
Sergey Poznyakoff 9 年 前
コミット
9a33077a7b
9 ファイル変更308 行追加7 行削除
  1. 23 1
      NEWS
  2. 1 1
      configure.ac
  3. 17 0
      doc/tar.texi
  4. 109 5
      src/names.c
  5. 3 0
      tests/Makefile.am
  6. 54 0
      tests/positional01.at
  7. 49 0
      tests/positional02.at
  8. 47 0
      tests/positional03.at
  9. 5 0
      tests/testsuite.at

+ 23 - 1
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
 

+ 1 - 1
configure.ac

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

+ 109 - 5
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;
 }
 

+ 3 - 0
tests/Makefile.am

@@ -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 - 0
tests/positional01.at

@@ -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 - 0
tests/positional02.at

@@ -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 - 0
tests/positional03.at

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

+ 5 - 0
tests/testsuite.at

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