4
0
Эх сурвалжийг харах

Improve handling of --test-label.

* src/list.c (print_volume_label): New function.
(print_header): Call print_volume_label.
(test_archive_label): New function.
* src/buffer.c (VOLUME_LABEL_APPEND): Remove.
(VOLUME_TEXT, VOLUME_TEXT_LEN): New macros
(drop_volume_label_suffix): New function.
(check_label_pattern): Use drop_volume_label_suffix.
* src/common.h (subcommand): New constant TEST_LABEL_SUBCOMMAND.
(test_label_option): Remove.
(drop_volume_label_suffix): New proto.
(test_archive_label): New proto.
* src/names.c (all_names_found): Remove test for test_label_option.
* src/tar.c (subcommand_string): Handle TEST_LABEL_SUBCOMMAND.
(set_subcommand_option): Improve diagnostics.
(parse_opt): Set subcommand if --test-label is given.
(main): Handle TEST_LABEL_SUBCOMMAND.
Sergey Poznyakoff 15 жил өмнө
parent
commit
28f2669b15
5 өөрчлөгдсөн 105 нэмэгдсэн , 41 устгасан
  1. 35 9
      src/buffer.c
  2. 5 3
      src/common.h
  3. 54 20
      src/list.c
  4. 0 2
      src/names.c
  5. 11 7
      src/tar.c

+ 35 - 9
src/buffer.c

@@ -36,9 +36,6 @@
 /* Number of retries before giving up on read.  */
 /* Number of retries before giving up on read.  */
 #define READ_ERROR_MAX 10
 #define READ_ERROR_MAX 10
 
 
-/* Globbing pattern to append to volume label if initial match failed.  */
-#define VOLUME_LABEL_APPEND " Volume [1-9]*"
-
 /* Variables.  */
 /* Variables.  */
 
 
 static tarlong prev_written;    /* bytes written on previous volumes */
 static tarlong prev_written;    /* bytes written on previous volumes */
@@ -1313,6 +1310,35 @@ try_new_volume ()
 }
 }
 
 
 
 
+#define VOLUME_TEXT " Volume "
+#define VOLUME_TEXT_LEN (sizeof VOLUME_TEXT - 1)
+
+char *
+drop_volume_label_suffix (const char *label)
+{
+  const char *p;
+  size_t len = strlen (label);
+
+  if (len < 1)
+    return NULL;
+  
+  for (p = label + len - 1; p > label && isdigit ((unsigned char) *p); p--)
+    ;
+  if (p > label && p - (VOLUME_TEXT_LEN - 1) > label)
+    {
+      p -= VOLUME_TEXT_LEN - 1;
+      if (memcmp (p, VOLUME_TEXT, VOLUME_TEXT_LEN) == 0)
+	{
+	  char *s = xmalloc ((len = p - label) + 1);
+	  memcpy (s, label, len);
+	  s[len] = 0;
+	  return s;
+	}
+    }
+
+  return NULL;
+}
+      
 /* Check LABEL against the volume label, seen as a globbing
 /* Check LABEL against the volume label, seen as a globbing
    pattern.  Return true if the pattern matches.  In case of failure,
    pattern.  Return true if the pattern matches.  In case of failure,
    retry matching a volume sequence number before giving up in
    retry matching a volume sequence number before giving up in
@@ -1329,12 +1355,12 @@ check_label_pattern (const char *label)
   if (!multi_volume_option)
   if (!multi_volume_option)
     return false;
     return false;
 
 
-  string = xmalloc (strlen (volume_label_option)
-                    + sizeof VOLUME_LABEL_APPEND + 1);
-  strcpy (string, volume_label_option);
-  strcat (string, VOLUME_LABEL_APPEND);
-  result = fnmatch (string, label, 0) == 0;
-  free (string);
+  string = drop_volume_label_suffix (label);
+  if (string)
+    {
+      result = fnmatch (string, volume_label_option, 0) == 0;
+      free (string);
+    }
   return result;
   return result;
 }
 }
 
 

+ 5 - 3
src/common.h

@@ -85,7 +85,8 @@ enum subcommand
   DIFF_SUBCOMMAND,		/* -d */
   DIFF_SUBCOMMAND,		/* -d */
   EXTRACT_SUBCOMMAND,		/* -x */
   EXTRACT_SUBCOMMAND,		/* -x */
   LIST_SUBCOMMAND,		/* -t */
   LIST_SUBCOMMAND,		/* -t */
-  UPDATE_SUBCOMMAND		/* -u */
+  UPDATE_SUBCOMMAND,		/* -u */
+  TEST_LABEL_SUBCOMMAND,        /* --test-label */
 };
 };
 
 
 GLOBAL enum subcommand subcommand_option;
 GLOBAL enum subcommand subcommand_option;
@@ -362,8 +363,6 @@ GLOBAL dev_t root_device;
 /* Unquote filenames */
 /* Unquote filenames */
 GLOBAL bool unquote_option;
 GLOBAL bool unquote_option;
 
 
-GLOBAL bool test_label_option; /* Test archive volume label and exit */
-
 /* Show file or archive names after transformation.
 /* Show file or archive names after transformation.
    In particular, when creating archive in verbose mode, list member names
    In particular, when creating archive in verbose mode, list member names
    as stored in the archive */
    as stored in the archive */
@@ -403,6 +402,8 @@ extern uintmax_t continued_file_size;
 extern uintmax_t continued_file_offset;
 extern uintmax_t continued_file_offset;
 extern off_t records_written;
 extern off_t records_written;
 
 
+char *drop_volume_label_suffix (const char *label);
+
 size_t available_space_after (union block *pointer);
 size_t available_space_after (union block *pointer);
 off_t current_block_ordinal (void);
 off_t current_block_ordinal (void);
 void close_archive (void);
 void close_archive (void);
@@ -578,6 +579,7 @@ uid_t uid_from_header (const char *buf, size_t size);
 uintmax_t uintmax_from_header (const char *buf, size_t size);
 uintmax_t uintmax_from_header (const char *buf, size_t size);
 
 
 void list_archive (void);
 void list_archive (void);
+void test_archive_label (void);
 void print_for_mkdir (char *dirname, int length, mode_t mode);
 void print_for_mkdir (char *dirname, int length, mode_t mode);
 void print_header (struct tar_stat_info *st, union block *blk,
 void print_header (struct tar_stat_info *st, union block *blk,
 	           off_t block_ordinal);
 	           off_t block_ordinal);

+ 54 - 20
src/list.c

@@ -672,7 +672,8 @@ from_header (char const *where0, size_t digs, char const *type,
 	{
 	{
 	  if (type && !silent)
 	  if (type && !silent)
 	    ERROR ((0, 0,
 	    ERROR ((0, 0,
-		    /* TRANSLATORS: %s is type of the value (gid_t, uid_t, etc.) */
+		    /* TRANSLATORS: %s is type of the value (gid_t, uid_t,
+		       etc.) */
 		    _("Blanks in header where numeric %s value expected"),
 		    _("Blanks in header where numeric %s value expected"),
 		    type));
 		    type));
 	  return -1;
 	  return -1;
@@ -1053,9 +1054,6 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
   int pad;
   int pad;
   int sizelen;
   int sizelen;
 
 
-  if (test_label_option && blk->header.typeflag != GNUTYPE_VOLHDR)
-    return;
-
   if (show_transformed_names_option)
   if (show_transformed_names_option)
     temp_name = st->file_name ? st->file_name : st->orig_file_name;
     temp_name = st->file_name ? st->file_name : st->orig_file_name;
   else
   else
@@ -1282,30 +1280,36 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
 }
 }
 
 
 
 
+void
+print_volume_label ()
+{
+  struct tar_stat_info vstat;
+  union block vblk;
+  enum archive_format dummy;
+
+  memset (&vblk, 0, sizeof (vblk));
+  vblk.header.typeflag = GNUTYPE_VOLHDR;
+  if (recent_global_header)
+    memcpy (vblk.header.mtime, recent_global_header->header.mtime,
+	    sizeof vblk.header.mtime);
+  tar_stat_init (&vstat);
+  assign_string (&vstat.file_name, ".");
+  decode_header (&vblk, &vstat, &dummy, 0);
+  assign_string (&vstat.file_name, volume_label);
+  simple_print_header (&vstat, &vblk, 0);
+  tar_stat_destroy (&vstat);
+}
+
 void
 void
 print_header (struct tar_stat_info *st, union block *blk,
 print_header (struct tar_stat_info *st, union block *blk,
 	      off_t block_ordinal)
 	      off_t block_ordinal)
 {
 {
   if (current_format == POSIX_FORMAT && !volume_label_printed && volume_label)
   if (current_format == POSIX_FORMAT && !volume_label_printed && volume_label)
     {
     {
-      struct tar_stat_info vstat;
-      union block vblk;
-      enum archive_format dummy;
-
+      print_volume_label ();
       volume_label_printed = true;
       volume_label_printed = true;
-
-      memset (&vblk, 0, sizeof (vblk));
-      vblk.header.typeflag = GNUTYPE_VOLHDR;
-      if (recent_global_header)
-	memcpy (vblk.header.mtime, recent_global_header->header.mtime,
-		sizeof vblk.header.mtime);
-      tar_stat_init (&vstat);
-      assign_string (&vstat.file_name, ".");
-      decode_header (&vblk, &vstat, &dummy, 0);
-      assign_string (&vstat.file_name, volume_label);
-      simple_print_header (&vstat, &vblk, block_ordinal);
-      tar_stat_destroy (&vstat);
     }
     }
+
   simple_print_header (st, blk, block_ordinal);
   simple_print_header (st, blk, block_ordinal);
 }
 }
 
 
@@ -1385,3 +1389,33 @@ skip_member (void)
       mv_end ();
       mv_end ();
     }
     }
 }
 }
+
+void
+test_archive_label ()
+{
+  base64_init ();
+  name_gather ();
+
+  open_archive (ACCESS_READ);
+  if (read_header (&current_header, &current_stat_info, false)
+      == HEADER_SUCCESS)
+    {
+      char *s = NULL;
+	
+      decode_header (current_header,
+		     &current_stat_info, &current_format, 0);
+      if (current_header->header.typeflag == GNUTYPE_VOLHDR)
+	assign_string (&volume_label, current_header->header.name);
+
+      if (volume_label
+	  && (name_match (volume_label)
+	      || (multi_volume_option
+		  && (s = drop_volume_label_suffix (volume_label))
+		  && name_match (s))))
+	if (verbose_option)
+	  print_volume_label ();
+      free (s);
+    }
+  close_archive ();
+  names_notfound ();
+}

+ 0 - 2
src/names.c

@@ -577,8 +577,6 @@ all_names_found (struct tar_stat_info *p)
   struct name const *cursor;
   struct name const *cursor;
   size_t len;
   size_t len;
 
 
-  if (test_label_option)
-    return true;
   if (!p->file_name || occurrence_option == 0 || p->had_trailing_slash)
   if (!p->file_name || occurrence_option == 0 || p->had_trailing_slash)
     return false;
     return false;
   len = strlen (p->file_name);
   len = strlen (p->file_name);

+ 11 - 7
src/tar.c

@@ -214,9 +214,10 @@ subcommand_string (enum subcommand c)
     case UPDATE_SUBCOMMAND:
     case UPDATE_SUBCOMMAND:
       return "-u";
       return "-u";
 
 
-    default:
-      abort ();
+    case TEST_LABEL_SUBCOMMAND:
+      return "--test-label";
     }
     }
+  abort ();
 }
 }
 
 
 void
 void
@@ -921,7 +922,7 @@ set_subcommand_option (enum subcommand subcommand)
   if (subcommand_option != UNKNOWN_SUBCOMMAND
   if (subcommand_option != UNKNOWN_SUBCOMMAND
       && subcommand_option != subcommand)
       && subcommand_option != subcommand)
     USAGE_ERROR ((0, 0,
     USAGE_ERROR ((0, 0,
-		  _("You may not specify more than one `-Acdtrux' option")));
+		  _("You may not specify more than one `-Acdtrux' or `--test-label' option")));
   
   
   subcommand_option = subcommand;
   subcommand_option = subcommand;
 }
 }
@@ -1612,8 +1613,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
       break;
       break;
       
       
     case TEST_LABEL_OPTION:
     case TEST_LABEL_OPTION:
-      set_subcommand_option (LIST_SUBCOMMAND);
-      test_label_option = true;
+      set_subcommand_option (TEST_LABEL_SUBCOMMAND);
       break;
       break;
       
       
     case 'T':
     case 'T':
@@ -2437,7 +2437,7 @@ decode_options (int argc, char **argv)
     old_files_option = UNLINK_FIRST_OLD_FILES;
     old_files_option = UNLINK_FIRST_OLD_FILES;
 
 
 
 
-  if (test_label_option)
+  if (subcommand_option == TEST_LABEL_SUBCOMMAND)
     {
     {
       /* --test-label is silent if the user has specified the label name to
       /* --test-label is silent if the user has specified the label name to
 	 compare against. */
 	 compare against. */
@@ -2472,6 +2472,7 @@ decode_options (int argc, char **argv)
     case EXTRACT_SUBCOMMAND:
     case EXTRACT_SUBCOMMAND:
     case LIST_SUBCOMMAND:
     case LIST_SUBCOMMAND:
     case DIFF_SUBCOMMAND:
     case DIFF_SUBCOMMAND:
+    case TEST_LABEL_SUBCOMMAND:
       for (archive_name_cursor = archive_name_array;
       for (archive_name_cursor = archive_name_array;
 	   archive_name_cursor < archive_name_array + archive_names;
 	   archive_name_cursor < archive_name_array + archive_names;
 	   archive_name_cursor++)
 	   archive_name_cursor++)
@@ -2578,7 +2579,7 @@ main (int argc, char **argv)
     {
     {
     case UNKNOWN_SUBCOMMAND:
     case UNKNOWN_SUBCOMMAND:
       USAGE_ERROR ((0, 0,
       USAGE_ERROR ((0, 0,
-		    _("You must specify one of the `-Acdtrux' options")));
+		    _("You must specify one of the `-Acdtrux' or `--test-label'  options")));
 
 
     case CAT_SUBCOMMAND:
     case CAT_SUBCOMMAND:
     case UPDATE_SUBCOMMAND:
     case UPDATE_SUBCOMMAND:
@@ -2612,6 +2613,9 @@ main (int argc, char **argv)
       diff_init ();
       diff_init ();
       read_and (diff_archive);
       read_and (diff_archive);
       break;
       break;
+
+    case TEST_LABEL_SUBCOMMAND:
+      test_archive_label ();
     }
     }
 
 
   if (totals_option)
   if (totals_option)