* 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.
/* Number of retries before giving up on read. */
#define READ_ERROR_MAX 10
-/* Globbing pattern to append to volume label if initial match failed. */
-#define VOLUME_LABEL_APPEND " Volume [1-9]*"
-
/* Variables. */
static tarlong prev_written; /* bytes written on previous volumes */
}
\f
+#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
pattern. Return true if the pattern matches. In case of failure,
retry matching a volume sequence number before giving up in
if (!multi_volume_option)
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;
}
DIFF_SUBCOMMAND, /* -d */
EXTRACT_SUBCOMMAND, /* -x */
LIST_SUBCOMMAND, /* -t */
- UPDATE_SUBCOMMAND /* -u */
+ UPDATE_SUBCOMMAND, /* -u */
+ TEST_LABEL_SUBCOMMAND, /* --test-label */
};
GLOBAL enum subcommand subcommand_option;
/* Unquote filenames */
GLOBAL bool unquote_option;
-GLOBAL bool test_label_option; /* Test archive volume label and exit */
-
/* Show file or archive names after transformation.
In particular, when creating archive in verbose mode, list member names
as stored in the archive */
extern uintmax_t continued_file_offset;
extern off_t records_written;
+char *drop_volume_label_suffix (const char *label);
+
size_t available_space_after (union block *pointer);
off_t current_block_ordinal (void);
void close_archive (void);
uintmax_t uintmax_from_header (const char *buf, size_t size);
void list_archive (void);
+void test_archive_label (void);
void print_for_mkdir (char *dirname, int length, mode_t mode);
void print_header (struct tar_stat_info *st, union block *blk,
off_t block_ordinal);
{
if (type && !silent)
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"),
type));
return -1;
int pad;
int sizelen;
- if (test_label_option && blk->header.typeflag != GNUTYPE_VOLHDR)
- return;
-
if (show_transformed_names_option)
temp_name = st->file_name ? st->file_name : st->orig_file_name;
else
}
+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
print_header (struct tar_stat_info *st, union block *blk,
off_t block_ordinal)
{
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;
-
- 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);
}
mv_end ();
}
}
+
+void
+test_archive_label ()
+{
+ base64_init ();
+ name_gather ();
+
+ open_archive (ACCESS_READ);
+ if (read_header (¤t_header, ¤t_stat_info, false)
+ == HEADER_SUCCESS)
+ {
+ char *s = NULL;
+
+ decode_header (current_header,
+ ¤t_stat_info, ¤t_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 ();
+}
struct name const *cursor;
size_t len;
- if (test_label_option)
- return true;
if (!p->file_name || occurrence_option == 0 || p->had_trailing_slash)
return false;
len = strlen (p->file_name);
case UPDATE_SUBCOMMAND:
return "-u";
- default:
- abort ();
+ case TEST_LABEL_SUBCOMMAND:
+ return "--test-label";
}
+ abort ();
}
void
if (subcommand_option != UNKNOWN_SUBCOMMAND
&& subcommand_option != subcommand)
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;
}
break;
case TEST_LABEL_OPTION:
- set_subcommand_option (LIST_SUBCOMMAND);
- test_label_option = true;
+ set_subcommand_option (TEST_LABEL_SUBCOMMAND);
break;
case 'T':
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
compare against. */
case EXTRACT_SUBCOMMAND:
case LIST_SUBCOMMAND:
case DIFF_SUBCOMMAND:
+ case TEST_LABEL_SUBCOMMAND:
for (archive_name_cursor = archive_name_array;
archive_name_cursor < archive_name_array + archive_names;
archive_name_cursor++)
{
case UNKNOWN_SUBCOMMAND:
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 UPDATE_SUBCOMMAND:
diff_init ();
read_and (diff_archive);
break;
+
+ case TEST_LABEL_SUBCOMMAND:
+ test_archive_label ();
}
if (totals_option)