Fix listing of volume labels (in particular in PAX archives).

* src/buffer.c (match_volume_label): Call set_volume_label.
(check_label_pattern): Get label string
as argument.
(match_volume_label): Handle volume labels stored in
global PAX headers.
* src/common.c (print_header,read_header): Change signature.
(read_header_primitive): Remove prototype.
* src/list.c (recent_global_header): New static.
(list_archive): Always print volume labels.
(read_header_primitive): Remove.
(read_header): Change the signature (all callers updated)
Save the recent global header.
(volume_label_printed): New static.
(simple_print_header): New function (ex-print_header).
(print_header): Change the signature (all callers updated).
For POSIX formats, print first volume header (if set).
* src/xheader.c (xheader_write_global): Write the data
accumulated in xhdr->stk even if keyword_global_override_list
is empty.
(xheader_read): On unexpected EOF, report error instead of
coredumping.
(XHDR_PROTECTED, XHDR_GLOBAL): New defines.
(struct xhdr_tab): Remove `protected' with `flags'. All uses updated.
(decg): If XHDR_GLOBAL bit is set, call the keyword's decode
method instead of adding it to `kwl'.

* src/compare.c: Update calls to read_header.
* src/create.c: Likewise.
* src/delete.c: Likewise.
* src/update.c: Likewise.
* src/extract.c: Likewise.
(extract_volhdr): Do not print "Reading <label>" statement, because
it is inconsistent: it is not printed if the volume begins with a
member continued from the previous volume.

* tests/label01.at: New testcase.
* tests/label02.at: New testcase.
* tests/Makefile.am, tests/testsuite.at: Add new testcases.
This commit is contained in:
Sergey Poznyakoff
2010-01-22 18:09:57 +02:00
parent cd91cd3c62
commit 166b7c7d02
13 changed files with 271 additions and 110 deletions

View File

@@ -1,6 +1,7 @@
/* POSIX extended headers for tar.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -440,30 +441,37 @@ xheader_write (char type, char *name, time_t t, struct xheader *xhdr)
void
xheader_write_global (struct xheader *xhdr)
{
char *name;
struct keyword_list *kp;
if (keyword_global_override_list)
{
struct keyword_list *kp;
if (!keyword_global_override_list)
return;
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 (), time (NULL), 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 (), time (NULL), xhdr);
free (name);
}
}
/* General Interface */
#define XHDR_PROTECTED 0x01
#define XHDR_GLOBAL 0x02
struct xhdr_tab
{
char const *keyword;
void (*coder) (struct tar_stat_info const *, char const *,
struct xheader *, void const *data);
void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
bool protect;
int flags;
};
/* This declaration must be extern, because ISO C99 section 6.9.2
@@ -491,7 +499,7 @@ xheader_protected_pattern_p (const char *pattern)
struct xhdr_tab const *p;
for (p = xhdr_tab; p->keyword; p++)
if (p->protect && fnmatch (pattern, p->keyword, 0) == 0)
if ((p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
return true;
return false;
}
@@ -502,7 +510,7 @@ xheader_protected_keyword_p (const char *keyword)
struct xhdr_tab const *p;
for (p = xhdr_tab; p->keyword; p++)
if (p->protect && strcmp (p->keyword, keyword) == 0)
if ((p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
return true;
return false;
}
@@ -633,7 +641,11 @@ decg (void *data, char const *keyword, char const *value,
size_t size __attribute__((unused)))
{
struct keyword_list **kwl = data;
xheader_list_append (kwl, keyword, value);
struct xhdr_tab const *tab = locate_handler (keyword);
if (tab && (tab->flags & XHDR_GLOBAL))
tab->decoder (data, keyword, value, size);
else
xheader_list_append (kwl, keyword, value);
}
void
@@ -695,6 +707,9 @@ xheader_read (struct xheader *xhdr, union block *p, size_t size)
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);
@@ -1491,51 +1506,53 @@ sparse_minor_decoder (struct tar_stat_info *st,
}
struct xhdr_tab const xhdr_tab[] = {
{ "atime", atime_coder, atime_decoder, false },
{ "comment", dummy_coder, dummy_decoder, false },
{ "charset", dummy_coder, dummy_decoder, false },
{ "ctime", ctime_coder, ctime_decoder, false },
{ "gid", gid_coder, gid_decoder, false },
{ "gname", gname_coder, gname_decoder, false },
{ "linkpath", linkpath_coder, linkpath_decoder, false },
{ "mtime", mtime_coder, mtime_decoder, false },
{ "path", path_coder, path_decoder, false },
{ "size", size_coder, size_decoder, false },
{ "uid", uid_coder, uid_decoder, false },
{ "uname", uname_coder, uname_decoder, false },
{ "atime", atime_coder, atime_decoder, 0 },
{ "comment", dummy_coder, dummy_decoder, 0 },
{ "charset", dummy_coder, dummy_decoder, 0 },
{ "ctime", ctime_coder, ctime_decoder, 0 },
{ "gid", gid_coder, gid_decoder, 0 },
{ "gname", gname_coder, gname_decoder, 0 },
{ "linkpath", linkpath_coder, linkpath_decoder, 0 },
{ "mtime", mtime_coder, mtime_decoder, 0 },
{ "path", path_coder, path_decoder, 0 },
{ "size", size_coder, size_decoder, 0 },
{ "uid", uid_coder, uid_decoder, 0 },
{ "uname", uname_coder, uname_decoder, 0 },
/* Sparse file handling */
{ "GNU.sparse.name", path_coder, path_decoder,
true },
XHDR_PROTECTED },
{ "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
true },
XHDR_PROTECTED },
{ "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder,
true },
XHDR_PROTECTED },
{ "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder,
true },
XHDR_PROTECTED },
{ "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder,
true },
XHDR_PROTECTED },
/* tar 1.14 - 1.15.90 keywords. */
{ "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true },
{ "GNU.sparse.size", sparse_size_coder, sparse_size_decoder,
XHDR_PROTECTED },
/* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x'
headers, and each of them was meaningful. It confilcted with POSIX specs,
which requires that "when extended header records conflict, the last one
given in the header shall take precedence." */
{ "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder,
true },
XHDR_PROTECTED },
{ "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
true },
XHDR_PROTECTED },
/* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
{ "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */,
sparse_map_decoder, false },
sparse_map_decoder, 0 },
{ "GNU.dumpdir", dumpdir_coder, dumpdir_decoder,
true },
XHDR_PROTECTED },
/* Keeps the tape/volume label. May be present only in the global headers.
Equivalent to GNUTYPE_VOLHDR. */
{ "GNU.volume.label", volume_label_coder, volume_label_decoder, true },
{ "GNU.volume.label", volume_label_coder, volume_label_decoder,
XHDR_PROTECTED | XHDR_GLOBAL },
/* These may be present in a first global header of the archive.
They provide the same functionality as GNUTYPE_MULTIVOL header.
@@ -1544,9 +1561,11 @@ struct xhdr_tab const xhdr_tab[] = {
GNU.volume.offset keeps the offset of the start of this volume,
otherwise kept in oldgnu_header.offset. */
{ "GNU.volume.filename", volume_label_coder, volume_filename_decoder,
true },
{ "GNU.volume.size", volume_size_coder, volume_size_decoder, true },
{ "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, true },
XHDR_PROTECTED | XHDR_GLOBAL },
{ "GNU.volume.size", volume_size_coder, volume_size_decoder,
XHDR_PROTECTED | XHDR_GLOBAL },
{ "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
XHDR_PROTECTED | XHDR_GLOBAL },
{ NULL, NULL, NULL, false }
{ NULL, NULL, NULL, 0 }
};