From 28f2669b15f2ddf5a25e4d7a7f36023ae0268c8b Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sun, 24 Jan 2010 16:52:24 +0200 Subject: [PATCH] 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. --- src/buffer.c | 44 ++++++++++++++++++++++++++++-------- src/common.h | 8 ++++--- src/list.c | 74 ++++++++++++++++++++++++++++++++++++++++++++---------------- src/names.c | 2 -- src/tar.c | 18 +++++++++------ 5 files changed, 105 insertions(+), 41 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index ed753034..f419dd7b 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -36,9 +36,6 @@ /* 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 */ @@ -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 pattern. Return true if the pattern matches. In case of failure, retry matching a volume sequence number before giving up in @@ -1329,12 +1355,12 @@ check_label_pattern (const char *label) 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 --git a/src/common.h b/src/common.h index 2af403c1..27121159 100644 --- a/src/common.h +++ b/src/common.h @@ -85,7 +85,8 @@ enum subcommand 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; @@ -362,8 +363,6 @@ GLOBAL dev_t root_device; /* 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 */ @@ -403,6 +402,8 @@ extern uintmax_t continued_file_size; 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); @@ -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); 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); diff --git a/src/list.c b/src/list.c index 3394e90d..5a341aad 100644 --- a/src/list.c +++ b/src/list.c @@ -672,7 +672,8 @@ from_header (char const *where0, size_t digs, char const *type, { 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; @@ -1053,9 +1054,6 @@ simple_print_header (struct tar_stat_info *st, union block *blk, 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 @@ -1283,29 +1281,35 @@ 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 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); } @@ -1385,3 +1389,33 @@ skip_member (void) 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 (); +} diff --git a/src/names.c b/src/names.c index 0e50aa40..ef011b70 100644 --- a/src/names.c +++ b/src/names.c @@ -577,8 +577,6 @@ all_names_found (struct tar_stat_info *p) 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); diff --git a/src/tar.c b/src/tar.c index a1185f6c..31e71efe 100644 --- a/src/tar.c +++ b/src/tar.c @@ -214,9 +214,10 @@ subcommand_string (enum subcommand c) case UPDATE_SUBCOMMAND: return "-u"; - default: - abort (); + case TEST_LABEL_SUBCOMMAND: + return "--test-label"; } + abort (); } void @@ -921,7 +922,7 @@ set_subcommand_option (enum subcommand subcommand) 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; } @@ -1612,8 +1613,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case TEST_LABEL_OPTION: - set_subcommand_option (LIST_SUBCOMMAND); - test_label_option = true; + set_subcommand_option (TEST_LABEL_SUBCOMMAND); break; case 'T': @@ -2437,7 +2437,7 @@ decode_options (int argc, char **argv) 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. */ @@ -2472,6 +2472,7 @@ decode_options (int argc, char **argv) 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++) @@ -2578,7 +2579,7 @@ main (int argc, char **argv) { 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: @@ -2612,6 +2613,9 @@ main (int argc, char **argv) diff_init (); read_and (diff_archive); break; + + case TEST_LABEL_SUBCOMMAND: + test_archive_label (); } if (totals_option) -- 2.11.4.GIT