[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Bug-tar] Labels in multivolume archives and long length filenames
From: |
Sergey Poznyakoff |
Subject: |
Re: [Bug-tar] Labels in multivolume archives and long length filenames |
Date: |
Fri, 22 Jan 2010 18:33:42 +0200 |
µÒÓÕÝØÙ <address@hidden> ha escrit:
> For gnu tar format everything is ok, but for posix tar format - can't
> read label.
Please, try the attached patch.
Regards,
Sergey
diff -pur orig/tar-1.22/src/buffer.c tar-1.22/src/buffer.c
--- orig/tar-1.22/src/buffer.c 2009-03-05 09:04:13.000000000 +0200
+++ tar-1.22/src/buffer.c 2010-01-22 18:15:25.000000000 +0200
@@ -1264,20 +1264,17 @@ try_new_volume ()
}
-/* Check the LABEL block 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,
retry matching a volume sequence number before giving up in
multi-volume mode. */
static bool
-check_label_pattern (union block *label)
+check_label_pattern (const char *label)
{
char *string;
bool result;
- if (! memchr (label->header.name, '\0', sizeof label->header.name))
- return false;
-
- if (fnmatch (volume_label_option, label->header.name, 0) == 0)
+ if (fnmatch (volume_label_option, label, 0) == 0)
return true;
if (!multi_volume_option)
@@ -1287,7 +1284,7 @@ check_label_pattern (union block *label)
+ sizeof VOLUME_LABEL_APPEND + 1);
strcpy (string, volume_label_option);
strcat (string, VOLUME_LABEL_APPEND);
- result = fnmatch (string, label->header.name, 0) == 0;
+ result = fnmatch (string, label, 0) == 0;
free (string);
return result;
}
@@ -1297,14 +1294,43 @@ check_label_pattern (union block *label)
static void
match_volume_label (void)
{
- union block *label = find_next_block ();
-
- if (!label)
+ if (!volume_label)
+ {
+ union block *label = find_next_block ();
+
+ if (!label)
+ FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),
+ quote (volume_label_option)));
+ if (label->header.typeflag == GNUTYPE_VOLHDR)
+ {
+ if (memchr (label->header.name, '\0', sizeof label->header.name))
+ assign_string (&volume_label, label->header.name);
+ else
+ {
+ volume_label = xmalloc (sizeof (label->header.name) + 1);
+ memcpy (volume_label, label->header.name,
+ sizeof (label->header.name));
+ volume_label[sizeof (label->header.name)] = 0;
+ }
+ }
+ else if (label->header.typeflag == XGLTYPE)
+ {
+ struct tar_stat_info st;
+ tar_stat_init (&st);
+ xheader_read (&st.xhdr, label,
+ OFF_FROM_HEADER (label->header.size));
+ xheader_decode (&st);
+ tar_stat_destroy (&st);
+ }
+ }
+
+ if (!volume_label)
FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),
quote (volume_label_option)));
- if (!check_label_pattern (label))
+
+ if (!check_label_pattern (volume_label))
FATAL_ERROR ((0, 0, _("Volume %s does not match %s"),
- quote_n (0, label->header.name),
+ quote_n (0, volume_label),
quote_n (1, volume_label_option)));
}
diff -pur orig/tar-1.22/src/list.c tar-1.22/src/list.c
--- orig/tar-1.22/src/list.c 2008-10-30 13:10:04.000000000 +0200
+++ tar-1.22/src/list.c 2010-01-22 18:15:25.000000000 +0200
@@ -33,6 +33,7 @@ union block *recent_long_name; /* recent
union block *recent_long_link; /* likewise, for long link */
size_t recent_long_name_blocks; /* number of blocks in recent_long_name
*/
size_t recent_long_link_blocks; /* likewise, for long link */
+union block *recent_global_header; /* Recent global header block */
static uintmax_t from_header (const char *, size_t, const char *,
uintmax_t, uintmax_t, bool, bool);
@@ -199,16 +200,50 @@ read_and (void (*do_something) (void))
names_notfound (); /* print names not found */
}
+static void print_header0 (struct tar_stat_info *st, union block *blk,
+ off_t block_ordinal);
+
/* Print a header block, based on tar options. */
void
list_archive (void)
{
+ static bool first_call = true;
off_t block_ordinal = current_block_ordinal ();
- /* Print the header block. */
+ /* Print the header block. */
+
decode_header (current_header, ¤t_stat_info, ¤t_format, 0);
+ if (first_call)
+ {
+ first_call = false;
+ if (volume_label)
+ {
+ if (verbose_option)
+ {
+ 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);
+ print_header0 (&vstat, &vblk, block_ordinal);
+ tar_stat_destroy (&vstat);
+ }
+ else
+ fprintf (stdlis, "%s\n", volume_label);
+ }
+ if (current_format == POSIX_FORMAT && test_label_option)
+ exit (0);
+ }
if (verbose_option)
- print_header (¤t_stat_info, block_ordinal);
+ print_header0 (¤t_stat_info, current_header, block_ordinal);
if (incremental_option)
{
@@ -391,6 +426,11 @@ read_header_primitive (bool raw_extended
else if (header->header.typeflag == XGLTYPE)
{
struct xheader xhdr;
+
+ if (!recent_global_header)
+ recent_global_header = xmalloc (sizeof *recent_global_header);
+ memcpy (recent_global_header, header,
+ sizeof *recent_global_header);
memset (&xhdr, 0, sizeof xhdr);
xheader_read (&xhdr, header,
OFF_FROM_HEADER (header->header.size));
@@ -1028,8 +1068,8 @@ static int ugswidth = 19;
USGWIDTH, some stairstepping may occur. */
static int datewidth = sizeof "YYYY-MM-DD HH:MM" - 1;
-void
-print_header (struct tar_stat_info *st, off_t block_ordinal)
+static void
+print_header0 (struct tar_stat_info *st, union block *blk, off_t block_ordinal)
{
char modes[11];
char const *time_stamp;
@@ -1045,7 +1085,7 @@ print_header (struct tar_stat_info *st,
int pad;
int sizelen;
- if (test_label_option && current_header->header.typeflag != GNUTYPE_VOLHDR)
+ if (test_label_option && blk->header.typeflag != GNUTYPE_VOLHDR)
return;
if (show_transformed_names_option)
@@ -1074,7 +1114,7 @@ print_header (struct tar_stat_info *st,
/* File type and modes. */
modes[0] = '?';
- switch (current_header->header.typeflag)
+ switch (blk->header.typeflag)
{
case GNUTYPE_VOLHDR:
modes[0] = 'V';
@@ -1144,8 +1184,8 @@ print_header (struct tar_stat_info *st,
/* Try parsing it as an unsigned integer first, and as a
uid_t if that fails. This method can list positive user
ids that are too large to fit in a uid_t. */
- uintmax_t u = from_header (current_header->header.uid,
- sizeof current_header->header.uid, 0,
+ uintmax_t u = from_header (blk->header.uid,
+ sizeof blk->header.uid, 0,
(uintmax_t) 0,
(uintmax_t) TYPE_MAXIMUM (uintmax_t),
false, false);
@@ -1154,7 +1194,7 @@ print_header (struct tar_stat_info *st,
else
{
sprintf (uform, "%ld",
- (long) UID_FROM_HEADER (current_header->header.uid));
+ (long) UID_FROM_HEADER (blk->header.uid));
user = uform;
}
}
@@ -1169,8 +1209,8 @@ print_header (struct tar_stat_info *st,
/* Try parsing it as an unsigned integer first, and as a
gid_t if that fails. This method can list positive group
ids that are too large to fit in a gid_t. */
- uintmax_t g = from_header (current_header->header.gid,
- sizeof current_header->header.gid, 0,
+ uintmax_t g = from_header (blk->header.gid,
+ sizeof blk->header.gid, 0,
(uintmax_t) 0,
(uintmax_t) TYPE_MAXIMUM (uintmax_t),
false, false);
@@ -1179,14 +1219,14 @@ print_header (struct tar_stat_info *st,
else
{
sprintf (gform, "%ld",
- (long) GID_FROM_HEADER (current_header->header.gid));
+ (long) GID_FROM_HEADER (blk->header.gid));
group = gform;
}
}
/* Format the file size or major/minor device numbers. */
- switch (current_header->header.typeflag)
+ switch (blk->header.typeflag)
{
case CHRTYPE:
case BLKTYPE:
@@ -1216,7 +1256,7 @@ print_header (struct tar_stat_info *st,
fprintf (stdlis, " %s", quotearg (temp_name));
- switch (current_header->header.typeflag)
+ switch (blk->header.typeflag)
{
case SYMTYPE:
fprintf (stdlis, " -> %s\n", quotearg (st->link_name));
@@ -1229,7 +1269,7 @@ print_header (struct tar_stat_info *st,
default:
{
char type_string[2];
- type_string[0] = current_header->header.typeflag;
+ type_string[0] = blk->header.typeflag;
type_string[1] = '\0';
fprintf (stdlis, _(" unknown file type %s\n"),
quote (type_string));
@@ -1263,7 +1303,7 @@ print_header (struct tar_stat_info *st,
case GNUTYPE_MULTIVOL:
strcpy (size,
STRINGIFY_BIGINT
- (UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset),
+ (UINTMAX_FROM_HEADER (blk->oldgnu_header.offset),
uintbuf));
fprintf (stdlis, _("--Continued at byte %s--\n"), size);
break;
@@ -1272,6 +1312,12 @@ print_header (struct tar_stat_info *st,
fflush (stdlis);
}
+void
+print_header (struct tar_stat_info *st, off_t block_ordinal)
+{
+ print_header0 (st, current_header, block_ordinal);
+}
+
/* Print a similar line when we make a directory automatically. */
void
print_for_mkdir (char *dirname, int length, mode_t mode)
diff -pur orig/tar-1.22/src/xheader.c tar-1.22/src/xheader.c
--- orig/tar-1.22/src/xheader.c 2008-11-30 14:30:54.000000000 +0200
+++ tar-1.22/src/xheader.c 2010-01-22 18:22:28.000000000 +0200
@@ -403,18 +403,22 @@ xheader_write (char type, char *name, st
void
xheader_write_global (struct xheader *xhdr)
{
- char *name;
- struct keyword_list *kp;
-
- if (!keyword_global_override_list)
- return;
+ if (keyword_global_override_list)
+ {
+ struct keyword_list *kp;
- xheader_init (xhdr);
- for (kp = keyword_global_override_list; kp; kp = kp->next)
- code_string (kp->value, kp->pattern, xhdr);
- xheader_finish (xhdr);
- xheader_write (XGLTYPE, name = xheader_ghdr_name (), xhdr);
- free (name);
+ xheader_init (xhdr);
+ for (kp = keyword_global_override_list; kp; kp = kp->next)
+ code_string (kp->value, kp->pattern, xhdr);
+ }
+ if (xhdr->stk)
+ {
+ char *name;
+
+ xheader_finish (xhdr);
+ xheader_write (XGLTYPE, name = xheader_ghdr_name (), xhdr);
+ free (name);
+ }
}
@@ -657,6 +661,9 @@ xheader_read (struct xheader *xhdr, unio
if (len > BLOCKSIZE)
len = BLOCKSIZE;
+ if (!p)
+ FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+
memcpy (&xhdr->buffer[j], p->buffer, len);
set_next_block_after (p);